1844 lines
99 KiB
C++
Executable file
1844 lines
99 KiB
C++
Executable file
// FICHIER : Hysteresis_bulk_2.cc
|
|
// CLASSE : Hysteresis_bulk
|
|
|
|
|
|
// 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 "ExceptionsLoiComp.h"
|
|
|
|
#include "Hysteresis_bulk.h"
|
|
|
|
// calcul de l'expression permettant d'obtenir la dérivée temporelle de la pression
|
|
// en fait il s'agit de l'équation constitutive
|
|
// utilisée dans la résolution explicite (runge par exemple) de l'équation constitutive
|
|
// 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
|
|
Vecteur& Hysteresis_bulk::Pression_point(const double & tau, const Vecteur & press_tau
|
|
, Vecteur& pres_point,int & erreur)
|
|
{ // récup de la contrainte à tau
|
|
double titi= tau; // sert à rien, c'est pour taire le compilo car tau ne sert pas directement
|
|
MPr_tau = press_tau(1);
|
|
// variation de sigma de R à tau
|
|
delta_MPr_R_a_tau = MPr_tau - MPr_R;
|
|
double deux_xmu = 2. * xmu; // pour simplifier
|
|
// calcul de QdeltaPression
|
|
double QdeltaPression = Abs(delta_MPr_R_a_tau);
|
|
|
|
// 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 ( QdeltaPression > (Qzero*depassement_Q0*wprime))
|
|
{erreur = 1;
|
|
//--- pour le debug
|
|
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (abs(Permet_affichage()) > 5))
|
|
cout << "\n QdeltaPression =" << QdeltaPression << " au lieu de "<< (Qzero*depassement_Q0*wprime)
|
|
<< " Hysteresis_bulk::Pression_point( " << endl ;
|
|
//--- fin debug
|
|
}
|
|
else // sinon on continue
|
|
{ erreur = 0;};
|
|
|
|
// calcul de Beta: ici ce n'est pas le même qu'en 3D, il est simplifié: voir doc
|
|
// on l'appel donc beta_P
|
|
double unsurwprimeQ0_puiss_np = 1./pow(wprime*Qzero,xnp);
|
|
double beta_P=0.; // init dans le cas où ne le calcul ne fonctionne pas après
|
|
if (QdeltaPression >= ConstMath::pasmalpetit)
|
|
// on ne calcul beta que si la norme de QdeltaSigma est significative
|
|
// sinon l'opération pow(QdeltaPression,xnp); peut poser pb via le log(QdeltaPression)
|
|
{ beta_P = pow(QdeltaPression,xnp) * unsurwprimeQ0_puiss_np;
|
|
};
|
|
// on considère que D est constant = delta_V/deltat et comme deltat = 1
|
|
// ==> = delta_V
|
|
double deuxmudeltaV = deux_xmu * delta_V ;
|
|
// formule : MPr_point = deux_xmu * delta_V(1- (1/(w'*Q0)^np) * QdeltaPression^np );
|
|
MPr_point = deuxmudeltaV*(1. - beta_P);
|
|
|
|
// on limite la variation de la dérivée de la contrainte
|
|
if (deuxmudeltaV > 0.)
|
|
{// cas d'une contrainte positive et normalement la dérivée doit évoluer entre 0. et 2mu * delta_V (c-a-d saturation)
|
|
if (MPr_point < 0. ) MPr_point = 0.;
|
|
if (MPr_point > deuxmudeltaV) MPr_point = deuxmudeltaV;
|
|
}
|
|
else
|
|
{// cas d'une contrainte négative et normalement la dérivée doit évoluer entre -2mu * delta_V (saturation) et 0
|
|
if (MPr_point < deuxmudeltaV ) MPr_point = deuxmudeltaV;
|
|
if (MPr_point > 0.) MPr_point = 0.;
|
|
};
|
|
|
|
// retour de la dérivée temporelle de la contrainte
|
|
pres_point(1) = MPr_point;
|
|
return pres_point;
|
|
};
|
|
|
|
// vérification de l'intégrité de la MPr calculée
|
|
// 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 Hysteresis_bulk::Verif_integrite_Pression(const double & , const Vecteur & MPr_tau_vect,int & erreur)
|
|
{ // récup de la contrainte à tau
|
|
MPr_tau = MPr_tau_vect(1);
|
|
// variation de sigma de R à tau
|
|
delta_MPr_R_a_tau = MPr_tau - MPr_R;
|
|
// calcul de QdeltaPression
|
|
double QdeltaPression = Abs(delta_MPr_R_a_tau);
|
|
// 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 ( QdeltaPression > (Qzero*depassement_Q0*wprime))
|
|
{erreur = 1;
|
|
//--- pour le debug
|
|
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (abs(Permet_affichage()) > 5))
|
|
cout << "\n QdeltaPression =" << QdeltaPression << " au lieu de "<< (Qzero*depassement_Q0*wprime)
|
|
<< " Hysteresis_bulk::Verif_integrite_Pression( " << endl ;
|
|
//--- fin debug
|
|
}
|
|
else // sinon on continue
|
|
{ erreur = 0;
|
|
};
|
|
};
|
|
|
|
// méthode permettant le calcul de la MPr à tdt par différente méthodes: linéarisation
|
|
// ou kutta
|
|
// en sortie calcul de :
|
|
// MPr_t___tdt, delta_MPr_tatdt
|
|
void Hysteresis_bulk::CalculPression_tdt(Tableau<double>& indicateurs_resolution)
|
|
{// le calcul de la contrainte s'effectue par la résolution de l'équation différentielle
|
|
// du schéma constitutif
|
|
// 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);
|
|
//-- 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
|
|
Vecteur val_initiale(1); // on démarre la recherche à la valeur à t
|
|
Vecteur racine(1); // dimensionnement init du résultat à 0.
|
|
Mat_pleine der_at_racine(1,1); // dimensionnement et init de la matrice dérivée à 0.
|
|
// comme la matrice n'est pas forcément définit positive on utilise CRAMER
|
|
der_at_racine.Change_Choix_resolution(CRAMER,RIEN_PRECONDITIONNEMENT);
|
|
int nb_incr_total,nb_iter_total; // variables intermédiaires d'indicateurs, pas utilisées pour l'instant
|
|
// 1== résolution de l'équation constitutive d'avancement discrétisée en euler implicite
|
|
bool conver = false; // init par défaut
|
|
try // on met le bloc sous surveillance
|
|
{
|
|
conver=alg_zero.Newton_raphson
|
|
(*this,&Hysteresis_bulk::Residu_constitutif,&Hysteresis_bulk::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)) || (abs(Permet_affichage()) > 0))
|
|
{cout << "\n non convergence 2 sur l'algo de la resolution du schema constitutif"
|
|
<< " abs_racine_max " << absracinemax
|
|
<< "\n Hysteresis_bulk::CalculPression_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 piloté ---
|
|
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (abs(Permet_affichage()) > 5))
|
|
cout << "\n Hysteresis_bulk::CalculContrainte_tdt "
|
|
<< "nombreIncre= " << nb_incr_total << " nb_iter_total= " << nb_iter_total << endl;
|
|
// --- fin debug piloté---
|
|
if (!conver)
|
|
{ cout << "\n non convergence sur l'algo de la resolution du schema constitutif"
|
|
<< "\n Hysteresis_bulk::CalculPression_tdt (...";
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();break;
|
|
};
|
|
delta_MPr_tatdt=racine(1); // récup de la solution
|
|
MPr_t___tdt = MPr_i___ + delta_MPr_tatdt;
|
|
// variation de -pression=MPr de R à tdt
|
|
rdelta_MPr_Ratdt = MPr_t___tdt - MPr_R;
|
|
// on vérifie l'amplitude de la pression calculée
|
|
{double QdeltaPression = Abs(rdelta_MPr_Ratdt); // calcul de QdeltaPression
|
|
if ( QdeltaPression > (Qzero*depassement_Q0*wprime))
|
|
{if ((ParaGlob::NiveauImpression() > 3)|| (abs(Permet_affichage()) > 0))
|
|
cout << "\n erreur10 fatale dans l'algo de la resolution du schema constitutif (en sortie de Newton) "
|
|
<< " concernant le niveau de saturation de la pression "
|
|
<< "\n QdeltaPression =" << QdeltaPression << " au lieu de "<< (Qzero*depassement_Q0*wprime)
|
|
<< "\n Hysteresis_bulk::CalculPression_tdt (..." << endl;
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();break;
|
|
}
|
|
// else if ( rdelta_MPr_Ratdt <= 0.)
|
|
// {if ((ParaGlob::NiveauImpression() > 3)|| (abs(Permet_affichage()) > 0))
|
|
// cout << "\n erreur20 fatale dans l'algo de la resolution du schema constitutif (en sortie de Newton) "
|
|
// << " concernant la nouvelle valeur de pression determinee "
|
|
// << "\n rdelta_MPr_Ratdt =" << rdelta_MPr_Ratdt << " qui devrait etre >= 0 " << "\n Hysteresis_bulk::CalculPression_tdt (..." << endl;
|
|
// // on génère une exception
|
|
// throw ErrNonConvergence_loiDeComportement();break;
|
|
// };
|
|
};
|
|
// on vérifie également le niveau de la pression totale calculée
|
|
{double AbsPression = Abs(MPr_t___tdt);
|
|
if ( AbsPression > (Qzero*depassement_Q0))
|
|
{if ((ParaGlob::NiveauImpression() > 3)|| (abs(Permet_affichage()) > 0))
|
|
cout << "\n erreur101 fatale dans l'algo de la resolution du schema constitutif (en sortie de Newton) "
|
|
<< " concernant le niveau de saturation de la pression "
|
|
<< "\n AbsPression =" << AbsPression << " au lieu de "<< (Qzero*depassement_Q0)
|
|
<< "\n Hysteresis_bulk::CalculPression_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
|
|
{// def des variables de calcul (peut-être ensuite à mettre dans le dimensionnement global)
|
|
Vecteur pres_initiale(1),derpres_initiale(1);
|
|
////--- debug ---
|
|
//#ifdef MISE_AU_POINT
|
|
//if (Abs(MPr_i___) > Qzero)
|
|
// { cout << "\n debug Hysteresis_bulk::CalculPression_tdt( "
|
|
// << " MPr_i___= "<< MPr_i___ << endl;
|
|
// };
|
|
//#endif
|
|
////----- fin debug ----
|
|
pres_initiale(1)=MPr_i___;
|
|
double tdeb=0.,tfi=1.;
|
|
// calcul de la dérivée initiale
|
|
int erreur=0; //init d'une erreur de calcul de MPr_point
|
|
Pression_point(tdeb,pres_initiale,derpres_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() > 0)
|
|
cout << "\n erreur dans l'algo de la resolution du schema constitutif"
|
|
<< " au niveau du calcul de la derivee initiale "
|
|
<< "\n Hysteresis_bulk::CalculPression_tdt() (..." << endl;
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();break;
|
|
};
|
|
|
|
Vecteur pres_finale(1),derpres_finale(1);
|
|
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,& Hysteresis_bulk::Pression_point,& Hysteresis_bulk::Verif_integrite_Pression
|
|
,pres_initiale,derpres_initiale
|
|
,tdeb,tfi,erreurAbsolue,erreurRelative
|
|
,pres_finale,derpres_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)) || (abs(Permet_affichage()) > 5))
|
|
cout << "\n Hysteresis_bulk::CalculContrainte_tdt "
|
|
<< " pres_finale= "<< pres_finale(1)
|
|
<< " nombreAppelF= " << nombreAppelF << " nb_step= " << nb_step << " erreur_maxi_global= "
|
|
<< erreur_maxi_global << endl;
|
|
// --- fin debug piloté---
|
|
// gestion de l'erreur de retour
|
|
double abssigmax=pres_finale.Max_val_abs();
|
|
if ((conver != 2) || (!isfinite(abssigmax)) || (isnan(abssigmax)) )
|
|
{ // on appel kutta45 sans gestion d'erreur !!
|
|
double deltat=tfi-tdeb;
|
|
Vecteur estime_erreur(1);
|
|
alg_edp.Runge_Kutta_step45(*this,& Hysteresis_bulk::Pression_point,& Hysteresis_bulk::Verif_integrite_Pression
|
|
,pres_initiale,derpres_initiale
|
|
,tdeb,deltat,pres_finale,estime_erreur);
|
|
if (estime_erreur(1) >= ConstMath::tresgrand)
|
|
{ // là on ne peut rien faire
|
|
if (ParaGlob::NiveauImpression() > 0)
|
|
cout << "\n erreur fatale dans l'algo de la resolution du schema constitutif"
|
|
<< " au niveau de l'appel directe de calcul de alg_edp.Runge_Kutta_step45 "
|
|
<< "\n Hysteresis_bulk::CalculPression_tdt() (..." << endl;
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();break;
|
|
}
|
|
else if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (abs(Permet_affichage()) > 3))
|
|
{cout << "\n erreur dans la resolution de l'equation constitutive avec Runge Kutta"
|
|
<< " indication de retour = " << conver << "appel direct de kutta45-> erreur estimee= "
|
|
<< estime_erreur(1)
|
|
<< "\n Hysteresis_bulk::CalculPression_tdt (..."<< endl;
|
|
// Sortie(1);
|
|
// pour le debug
|
|
// if ((Dabs(estime_erreur(1)) > 10) || (Dabs(pres_finale(1)) > 10))
|
|
// alg_edp.Runge_Kutta_step45(*this,& Hysteresis_bulk::Sigma_point,pres_initiale,derpres_initiale
|
|
// ,tdeb,deltat,pres_finale,estime_erreur);
|
|
|
|
};
|
|
double abssigmax=pres_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 Hysteresis_bulk::CalculPression_tdt (..."<< endl;
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();
|
|
Sortie(1);
|
|
};
|
|
};
|
|
|
|
// récup des résultats
|
|
MPr_t___tdt=pres_finale(1);
|
|
delta_MPr_tatdt = MPr_t___tdt - MPr_i___;
|
|
// variation de -pression=MPr de R à tdt
|
|
rdelta_MPr_Ratdt = MPr_t___tdt - MPr_R;
|
|
// on vérifie l'amplitude de la pression calculée
|
|
{double QdeltaPression = Abs(rdelta_MPr_Ratdt); // calcul de QdeltaPression
|
|
if ( QdeltaPression > (Qzero*depassement_Q0*wprime))
|
|
{if ((ParaGlob::NiveauImpression() > 3)|| (abs(Permet_affichage()) > 0))
|
|
cout << "\n erreur1005 fatale dans l'algo de la resolution du schema constitutif (en sortie de kutta) "
|
|
<< " concernant le niveau de saturation de la pression "
|
|
<< "\n QdeltaPression =" << QdeltaPression << " au lieu de "<< (Qzero*depassement_Q0*wprime)
|
|
<< "\n Hysteresis_bulk::CalculPression_tdt (..." << endl;
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();break;
|
|
}
|
|
// else if ( rdelta_MPr_Ratdt <= 0.)
|
|
// {if ((ParaGlob::NiveauImpression() > 3)|| (abs(Permet_affichage()) > 0))
|
|
// cout << "\n erreur21 fatale dans l'algo de la resolution du schema constitutif (en sortie de Newton) "
|
|
// << " concernant la nouvelle valeur de pression determinee "
|
|
// << "\n rdelta_MPr_Ratdt =" << rdelta_MPr_Ratdt << " qui devrait etre >= 0 " << "\n Hysteresis_bulk::CalculPression_tdt (..." << endl;
|
|
// // on génère une exception
|
|
// throw ErrNonConvergence_loiDeComportement();break;
|
|
// };
|
|
};
|
|
// on vérifie également le niveau de la pression totale calculée (non,**** à voir )
|
|
// en fait celle-ci peut-être momentanément supérieur à Qzero, en fait le total
|
|
// ne peut pas être supérieur à Qzero(1.+wprime), qui est le cas avant coïncidence
|
|
// d'un point sur une branche secondaire qui démarre près de la saturation
|
|
{double AbsPression = Abs(MPr_t___tdt);
|
|
if ( AbsPression > (Qzero*(1.+wprime)*depassement_Q0))
|
|
{if ((ParaGlob::NiveauImpression() > 3)|| (abs(Permet_affichage()) > 0))
|
|
cout << "\n erreur1015 fatale dans l'algo de la resolution du schema constitutif (en sortie de kutta) "
|
|
<< " concernant le niveau de saturation de la pression (meme transitoirement avant coincidence) "
|
|
<< "\n AbsPression =" << AbsPression << " au lieu de "<< (Qzero*(1.+wprime)*depassement_Q0)
|
|
<< "\n Hysteresis_bulk::CalculPression_tdt (..."
|
|
<< endl;
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();break;
|
|
|
|
};
|
|
};
|
|
|
|
break;
|
|
}
|
|
case 3: // cas de la linéarisation de l'équation et où on impose la limitation lorsque l'on atteind la saturation
|
|
{// ----- pour ce faire on appelle une methode de recherche de zero
|
|
Vecteur val_initiale(1); // on démarre la recherche à la valeur à t
|
|
Vecteur racine(1); // dimensionnement init du résultat à 0.
|
|
Mat_pleine der_at_racine(1,1); // dimensionnement et init de la matrice dérivée à 0.
|
|
// comme la matrice n'est pas forcément définit positive on utilise CRAMER
|
|
der_at_racine.Change_Choix_resolution(CRAMER,RIEN_PRECONDITIONNEMENT);
|
|
int nb_incr_total,nb_iter_total; // variables intermédiaires d'indicateurs, pas utilisées pour l'instant
|
|
// 1== résolution de l'équation constitutive d'avancement discrétisée en euler implicite
|
|
bool conver = false; // init par défaut
|
|
try // on met le bloc sous surveillance
|
|
{
|
|
conver=alg_zero.Newton_raphson
|
|
(*this,&Hysteresis_bulk::Residu_constitutif,&Hysteresis_bulk::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)) || (abs(Permet_affichage()) > 0))
|
|
{cout << "\n non convergence 29 sur l'algo de la resolution du schema constitutif"
|
|
<< " abs_racine_max " << absracinemax
|
|
<< "\n Hysteresis_bulk::CalculPression_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 piloté ---
|
|
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (abs(Permet_affichage()) > 5))
|
|
cout << "\n Hysteresis_bulk::CalculContrainte_tdt "
|
|
<< "nombreIncre= " << nb_incr_total << " nb_iter_total= " << nb_iter_total << endl;
|
|
// --- fin debug piloté---
|
|
if (!conver)
|
|
{ cout << "\n non convergence sur l'algo de la resolution du schema constitutif"
|
|
<< "\n Hysteresis_bulk::CalculPression_tdt (...";
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();break;
|
|
};
|
|
delta_MPr_tatdt=racine(1); // récup de la solution
|
|
MPr_t___tdt = MPr_i___ + delta_MPr_tatdt;
|
|
// variation de -pression=MPr de R à tdt
|
|
rdelta_MPr_Ratdt = MPr_t___tdt - MPr_R;
|
|
// on vérifie l'amplitude de la pression calculée
|
|
{double QdeltaPression = Abs(rdelta_MPr_Ratdt); // calcul de QdeltaPression
|
|
if ( QdeltaPression > (Qzero*depassement_Q0*wprime))
|
|
{// dans ce cas on impose la saturation
|
|
QdeltaPression = (Qzero*depassement_Q0*wprime);
|
|
rdelta_MPr_Ratdt = QdeltaPression * DSigne(rdelta_MPr_Ratdt);
|
|
MPr_t___tdt = rdelta_MPr_Ratdt + MPr_R;
|
|
delta_MPr_tatdt = MPr_t___tdt - MPr_i___;
|
|
|
|
|
|
if ((ParaGlob::NiveauImpression() > 3)|| (abs(Permet_affichage()) > 0))
|
|
cout << "\n ** warning dans l'algo de la resolution du schema constitutif (en sortie de Newton) "
|
|
<< " concernant le niveau de saturation de la pression "
|
|
<< "\n QdeltaPression =" << QdeltaPression << " au lieu de "<< (Qzero*depassement_Q0*wprime)
|
|
<< "\n Hysteresis_bulk::CalculPression_tdt (..." << endl;
|
|
}
|
|
// else if ( rdelta_MPr_Ratdt <= 0.)
|
|
// {if ((ParaGlob::NiveauImpression() > 3)|| (abs(Permet_affichage()) > 0))
|
|
// cout << "\n erreur20 fatale dans l'algo de la resolution du schema constitutif (en sortie de Newton) "
|
|
// << " concernant la nouvelle valeur de pression determinee "
|
|
// << "\n rdelta_MPr_Ratdt =" << rdelta_MPr_Ratdt << " qui devrait etre >= 0 " << "\n Hysteresis_bulk::CalculPression_tdt (..." << endl;
|
|
// // on génère une exception
|
|
// throw ErrNonConvergence_loiDeComportement();break;
|
|
// };
|
|
};
|
|
// on vérifie également le niveau de la pression totale calculée
|
|
{double AbsPression = Abs(MPr_t___tdt);
|
|
if ( AbsPression > (Qzero*depassement_Q0))
|
|
{ // dans ce cas on impose la saturation
|
|
AbsPression = (Qzero*depassement_Q0);
|
|
MPr_t___tdt = AbsPression * DSigne(MPr_t___tdt);
|
|
if ((ParaGlob::NiveauImpression() > 3)|| (abs(Permet_affichage()) > 0))
|
|
cout << "\n ** warning dans l'algo de la resolution du schema constitutif (en sortie de Newton) "
|
|
<< " concernant le niveau de saturation de la pression "
|
|
<< "\n AbsPression =" << AbsPression << " au lieu de "<< (Qzero*depassement_Q0)
|
|
<< "\n Hysteresis_bulk::CalculPression_tdt (..." << endl;
|
|
};
|
|
};
|
|
break;
|
|
}
|
|
};
|
|
|
|
};
|
|
|
|
// =============== 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& Hysteresis_bulk::Residu_constitutif (const double & alpha,const Vecteur & x, int& test)
|
|
{ // tout d'abord on récupère les pressions
|
|
rdelta_MPr_tatdt = x(1); // accroissement de -pression=MPr : de t à tdt
|
|
// variation de -pression=MPr de R à tdt
|
|
rdelta_MPr_Ratdt = MPr_i___ + rdelta_MPr_tatdt - MPr_R;
|
|
double deux_xmu = 2. * xmu; // pour simplifier
|
|
// calcul de QdeltaPression
|
|
double QdeltaPression = Abs(rdelta_MPr_Ratdt);
|
|
// calcul de Beta: ici ce n'est pas le même qu'en 3D, il est simplifié: voir doc
|
|
// on l'appel donc beta_P
|
|
double unsurwprimeQ0_puiss_np = 1./pow(wprime*Qzero,xnp);
|
|
double beta_P=0.; // init dans le cas où ne le calcul ne fonctionne pas après
|
|
if (QdeltaPression >= ConstMath::petit)
|
|
// on ne calcul beta que si la norme de QdeltaSigma est significative
|
|
// sinon l'opération pow(QdeltaPression,xnp); peut poser pb via le log(QdeltaPression)
|
|
{ beta_P = pow(QdeltaPression,xnp) * unsurwprimeQ0_puiss_np;
|
|
};
|
|
// on considère que D est constant = delta_V/deltat et comme deltat = 1
|
|
// ==> = delta_V
|
|
double deuxmudeltaV = deux_xmu * delta_V ;
|
|
// calcul du résidu
|
|
residuBH = rdelta_MPr_tatdt
|
|
- alpha * deuxmudeltaV * (1.- beta_P);
|
|
// a priori ici pas de pb de calcul
|
|
test = 1;
|
|
// retour du résidu
|
|
residu(1) = residuBH;
|
|
return residu;
|
|
};
|
|
|
|
// calcul de la matrice tangente de la résolution de l'équation constitutive
|
|
// . 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& Hysteresis_bulk::Mat_tangente_constitutif
|
|
(const double & alpha,const Vecteur & x, Vecteur& residu, int& test)
|
|
{ // récupération du vecteur delta_Mpr
|
|
rdelta_MPr_tatdt = x(1);
|
|
rdelta_MPr_Ratdt = MPr_i___ + rdelta_MPr_tatdt - MPr_R;
|
|
double deux_xmu = 2. * xmu; // pour simplifier
|
|
// ne sert plus delta__alpha_V = alpha * delta_V; // limitation de la charge
|
|
// calcul de QdeltaPression
|
|
double QdeltaPression = Abs(rdelta_MPr_Ratdt);
|
|
|
|
// calcul de Beta: ici ce n'est pas le même qu'en 3D, il est simplifié: voir doc
|
|
// on l'appel donc beta_P
|
|
double unsurwprimeQ0_puiss_np = 1./pow(wprime*Qzero,xnp);
|
|
double beta_P=0.; // init dans le cas où ne le calcul ne fonctionne pas après
|
|
double QdeltaPression_puiss_npmoins1 = 0.; // sert pour la matrice tangente
|
|
if (QdeltaPression >= ConstMath::petit)
|
|
// on ne calcul beta que si la norme de QdeltaSigma est significative
|
|
// sinon l'opération pow(QdeltaPression,xnp); peut poser pb via le log(QdeltaPression)
|
|
{ beta_P = pow(QdeltaPression,xnp) * unsurwprimeQ0_puiss_np;
|
|
QdeltaPression_puiss_npmoins1 = pow(QdeltaPression,xnp-1.);
|
|
};
|
|
// on considère que D est constant = delta_V/deltat et comme deltat = 1
|
|
// ==> = delta_V
|
|
double deuxmudeltaV = deux_xmu * delta_V ;
|
|
// calcul du résidu
|
|
residuBH = rdelta_MPr_tatdt
|
|
- alpha * deuxmudeltaV * (1.- beta_P);
|
|
residu(1) = residuBH;
|
|
|
|
// maintenant on s'occupe de la matrice tangente
|
|
double d_res_dMP = 1.
|
|
- alpha * deuxmudeltaV * unsurwprimeQ0_puiss_np
|
|
* xnp * QdeltaPression_puiss_npmoins1
|
|
* DSigne(rdelta_MPr_Ratdt);
|
|
// a priori ici pas de pb de calcul
|
|
test = 1;
|
|
// retour de la matrice tangente
|
|
derResidu(1,1)=d_res_dMP;
|
|
return derResidu;
|
|
};
|
|
|
|
// calcul de l'opérateur tangent : dsigma/depsilon, dans le cas d'un repère ortho-normé ou non
|
|
// T_d_Mpres_d_V: représente la variation de la MPr par rapport à V
|
|
// dsig_deps : opérateur tangent 3D
|
|
void Hysteresis_bulk::Dsig_depsilon
|
|
(double& T_d_Mpres_d_V,bool en_base_orthonormee,const Tenseur3HH & gijHH_tdt, TenseurHHHH* dsig_deps_
|
|
,const double & V_tdt)
|
|
//TenseurQ1geneBHBH& Hysteresis_bulk::Dsig_depsilon(TenseurQ1geneBHBH& dsig_deps)
|
|
{ // calcul des termes élémentaires de l'équation constitutive
|
|
double deux_xmu = 2. * xmu; // pour simplifier
|
|
// calcul de QdeltaPression
|
|
double QdeltaPression = Abs(delta_MPr_Ratdt);
|
|
double unsurQdeltaPression; // on limite la valeur par exemple pour le démarrage
|
|
if ( Dabs(QdeltaPression) > ConstMath::pasmalpetit) {unsurQdeltaPression=1./QdeltaPression;}
|
|
else {unsurQdeltaPression = ConstMath::grand;};
|
|
// calcul de Beta
|
|
double unsurwprimeQ0_puiss_np = 1./pow(wprime*Qzero,xnp);
|
|
|
|
// calcul de Beta: ici ce n'est pas le même qu'en 3D, il est simplifié: voir doc
|
|
// on l'appel donc beta_P
|
|
double beta_P=0.; // init dans le cas où ne le calcul ne fonctionne pas après
|
|
if (QdeltaPression >= ConstMath::petit)
|
|
// on ne calcul beta que si la norme de QdeltaSigma est significative
|
|
// sinon l'opération pow(QdeltaPression,xnp); peut poser pb via le log(QdeltaPression)
|
|
{ beta_P = pow(QdeltaPression,xnp) * unsurwprimeQ0_puiss_np;
|
|
};
|
|
|
|
// calcul de la variation de -P / à V
|
|
T_d_Mpres_d_V = deux_xmu * (1 - beta_P);
|
|
|
|
// -- calcul de dsigma / d_eps
|
|
if (dsig_deps_ != NULL)
|
|
{Tenseur3HHHH & dsig_deps = *((Tenseur3HHHH*) dsig_deps_);
|
|
// le traitement dépends du type de déformation
|
|
switch (type_de_deformation)
|
|
{case DEFORMATION_STANDART : case DEFORMATION_POUTRE_PLAQUE_STANDART :
|
|
// cas d'une déformation d'Almansi
|
|
{ // on a dans ce cas : d I3/ d eps_{ij} = 2 * I3 * g^{ij}, avec I3 = V^2, d'où
|
|
// d V / d eps_{ij} = V * g^{ij}
|
|
//Tenseur3HH d_V_d_epsij_HH = V_tdt * gijHH_tdt;
|
|
// au final : d sig / d eps_{ij} = d sig / d V * d V / d eps_{ij}
|
|
// mais sig = -P Id = Id * (-P) -> d sig = Id * (- d_P) + (-P) * d_Id d'où
|
|
// d sig / d eps_{ij} = (- d_P / d V) * (Id tensoriel d V / d eps_{ij})
|
|
// + (-P) * (d_Id / d eps_{ij})
|
|
// en composante:
|
|
// d sig^{ij} / d eps_{kl} = (- d_P / d V) * V * (g^{ij} * g^{kl})
|
|
// + (-P) * (-2) * (g^{ik}* g^{jl})
|
|
I_x_I_HHHH=Tenseur3HHHH::Prod_tensoriel(gijHH_tdt,gijHH_tdt);
|
|
I_xbarre_I_HHHH=Tenseur3HHHH::Prod_tensoriel_barre(gijHH_tdt,gijHH_tdt);
|
|
dsig_deps += T_d_Mpres_d_V * I_x_I_HHHH;
|
|
dsig_deps -= (2. * MPr_t___tdt) * I_xbarre_I_HHHH;
|
|
};
|
|
break;
|
|
default :
|
|
cout << "\nErreur : type de deformation qui n'est pas actuellement pris en compte, type= "
|
|
<< Nom_type_deformation(type_de_deformation);
|
|
cout << "\n Hysteresis_bulk::Dsig_depsilon (... \n";
|
|
Sortie(1);
|
|
};
|
|
};
|
|
|
|
//----- vérife avec dérivée numérique
|
|
// double divise = delta_V;
|
|
// if (Dabs(divise) <= ConstMath::pasmalpetit) divise = Signe(divise,ConstMath::pasmalpetit);
|
|
// double optang_num =(MPr_t___tdt(1,1)-MPr_i___(1,1))/divise;
|
|
// if (Dabs(optang_num) <= ConstMath::pasmalpetit) optang_num = Signe(optang_num,ConstMath::pasmalpetit);
|
|
//
|
|
// dsig_deps.Change(1,1,1,1,optang_num);
|
|
//
|
|
// cout << "\n optang= " << optang << " approchee= "
|
|
// << optang_num;
|
|
|
|
};
|
|
|
|
|
|
// --------------- méthodes internes ---------------:
|
|
// affinage d'un point de coincidence
|
|
// ramène true si le traitement est exactement terminé, sinon false, ce qui signifie qu'il
|
|
// faut encore continuer à utiliser l'équation d'évolution
|
|
// premiere_charge : indique si c'est oui ou non une coincidence avec la première charge
|
|
// pt_sur_principal : indique si oui ou non les pointeurs iafct et iatens pointent sur les listes
|
|
// principales
|
|
// iatens_princ et iafct_princ: pointeurs sur les listes principales
|
|
bool Hysteresis_bulk::Coincidence(bool & aucun_pt_inversion,double& unSur_wprimeCarre,bool premiere_charge
|
|
,SaveResulHysteresis_bulk & save_resul,double& W_a
|
|
,List_io <double>::iterator& iatens,List_io <double>::iterator& iafct
|
|
,bool& pt_sur_principal,List_io <double>::iterator& iatens_princ,List_io <double>::iterator& iafct_princ
|
|
,double& delta_W_a,bool force_coincidence,const double& MPr_tdt)
|
|
|
|
{ // tout d'abord on vérifie que l'on n'est pas exactement à un point de
|
|
// coincidence à la précision près
|
|
double c = (W_a - delta_W_a) - *iafct;
|
|
bool coin_exacte = false; // drapeau indiquant si l'on a une coincidence exacte ou pas
|
|
// si cc est positif, cela signifie qu'au pas précédent on n'a pas bien détecté une coincidence
|
|
// ou que c'est un pb de zero
|
|
// on considère alors que le point actuel est un point de coïncidence à la précision près et donc
|
|
// on finit le traitement
|
|
|
|
double tol_coincidence_reelle = tolerance_coincidence;
|
|
if (tolerance_coincidence < 0) // si l'indication est négative , cela veut dire que l'on veut une grandeur relative
|
|
tol_coincidence_reelle = MaX(-tolerance_coincidence * (*iafct),-tolerance_coincidence);
|
|
|
|
if ((Abs(W_a - *iafct) <= tol_coincidence_reelle) || force_coincidence
|
|
|| (c >= 0.)) // !!! rajoue du cas c>0 pour voir !!!!
|
|
{// on est dans le cas où l'on a une coïncidence exacte à la précision "tolerance_coincidence" près
|
|
// mais dans tous les cas on a rayon_tdt > Q_OiaR sinon on n'aurait pas de coïncidence
|
|
// on signale qu'il y a une coincidence exacte (pour le retour de la méthode Coincidence)
|
|
// gestion des pointeurs
|
|
Gestion_pointeur_coincidence(unSur_wprimeCarre,save_resul,W_a
|
|
,aucun_pt_inversion
|
|
,iatens,iafct,pt_sur_principal
|
|
,iatens_princ,iafct_princ,MPr_tdt);
|
|
return true;
|
|
};
|
|
// --- sinon on continue mais le traitement ne sera pas fini !!
|
|
|
|
// dans une première étape on tente de calculer plus précisemment le point d'inversion,
|
|
// en supposant une approximation linéaire de l'évolution de sigma sur le pas de temps:
|
|
// cf thèse nicolas: (9.56):
|
|
// avec cependant un facteur 4 qui manque sur a: la formule 9.56 est fausse
|
|
// la formule 9.55 montre qu'il faut un facteur 4
|
|
bool bon_calcul = false; // permet de savoir si le calcul précis est correcte
|
|
double a = 4.* unSur_wprimeCarre * (delta_V * delta_MPr_tatdt);
|
|
double b = 2. * unSur_wprimeCarre * (delta_V * delta_MPr_Rat);
|
|
// #ifdef MISE_AU_POINT
|
|
// if(!premiere_charge)
|
|
// if (c >= 0.) // signifie qu'au pas précédent on n'a pas bien détecté une coincidence
|
|
// { cout << "\n erreur algo coincidence : 1 "
|
|
// << "\n Hysteresis_bulk::Coincidence(... ";
|
|
// Sortie(1);
|
|
// }
|
|
// #endif
|
|
// recherche de racine
|
|
double racine1,racine2; int cas;
|
|
alg_zero.SecondDegre(a,b,c,racine1,racine2,cas);
|
|
// traitement suivant les différents cas
|
|
switch (cas)
|
|
{ case 1: // deux racines distinctes
|
|
{ // normalement les deux racines sont de signe opposé, seule la positive <=1 est recevable
|
|
if (racine1*racine2 <=0.)
|
|
{// on regarde si racine2 <= 1 ce qui est le cas normal
|
|
if (racine2 <= 1.) // racine2 est la plus grande donc positive
|
|
// cas normal, on valide la procédure
|
|
{ bon_calcul = true;}
|
|
#ifdef MISE_AU_POINT
|
|
else // sinon cela signifie que la méthode n'est pas bonne
|
|
{ if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (abs(Permet_affichage()) > 0))
|
|
cout << "\n warning algo coincidence, dans la recherche des racines de l'equa 2 degre "
|
|
<< " la seconde racine " << racine2 << " est superieur a 1"
|
|
<< "\n Hysteresis_bulk::Coincidence(... ";
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
// normalement a >=0 donc avec c <0 on ne doit pas avoir 2 racines du même signe
|
|
if(!premiere_charge) // sauf dans le cas de la première charge
|
|
{ if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (abs(Permet_affichage()) > 0))
|
|
cout << "\n erreur algo coincidence, dans la recherche des racines de l'equa 2 degre "
|
|
<< " les deux racines sont du meme signe ??, a= " <<a<<" c= " << c << " racine1= "
|
|
<< racine1 << " racine2= " << racine1
|
|
<< "\n Hysteresis_bulk::Coincidence(... ";
|
|
}
|
|
#endif
|
|
// on regarde si une des racines convient
|
|
// a priori on garde la plus grande, si les deux conviennent
|
|
double la_plus_grande = MaX(racine1,racine2);
|
|
if ((la_plus_grande>0.) && (la_plus_grande<1.))
|
|
{ racine2=la_plus_grande; bon_calcul = true;}
|
|
else // sinon on test l'autre
|
|
{ double la_plus_petite = MiN(racine1,racine2);
|
|
if ((la_plus_petite>0.) && (la_plus_petite<1.))
|
|
{ racine2=la_plus_petite; bon_calcul = true;}
|
|
// sinon rien tous les autres cas sont mauvais
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 2: // deux racines identiques
|
|
{ // normalement la racine doit être comprise entre 0 et 1, sinon non recevable
|
|
if ((racine2>=0.) && (racine2 <= 1.))
|
|
// cas normal, on valide la procédure
|
|
{ bon_calcul = true;}
|
|
// tous les autres cas sont mauvais
|
|
break;
|
|
}
|
|
case -3: // une racine simple
|
|
{ // normalement la racine doit être comprise entre 0 et 1, sinon non recevable
|
|
if ((racine1>=0.) && (racine1 <= 1.))
|
|
// cas normal, on valide la procédure
|
|
{ bon_calcul = true;
|
|
racine2=racine1; // pour la suite
|
|
}
|
|
// tous les autres cas sont mauvais
|
|
break;
|
|
}
|
|
};
|
|
|
|
if (!bon_calcul)
|
|
// cas où la recherche fine avec la résolution de l'équat du second degré n'a pas marché
|
|
{ // on utilise une interpolation plus grossière à l'aide de la fonction de charge
|
|
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (abs(Permet_affichage()) > 0))
|
|
cout << "\n on passe par l'interpolation de la fonction d'aide";
|
|
double W_t=W_a - delta_W_a;
|
|
racine2 = (*iafct - W_t) / delta_W_a;
|
|
// normalement racine2 est compris entre 0 et 1
|
|
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (abs(Permet_affichage()) > 0))
|
|
{if ( (racine2 < 0.) || (racine2 > 1.))
|
|
{ cout << "\n erreur algo coincidence, dans la recherche de racine2 a l'aide de la fonction de charge "
|
|
<< " W_ref= " <<*iafct<<" W_t= " << W_t << " delta_W_a= " << delta_W_a
|
|
<< "\n Hysteresis_bulk::Coincidence(... ";
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();
|
|
}
|
|
else { cout << "\n nouvelle racine = "<< racine2 ;} ;
|
|
};
|
|
};
|
|
|
|
// maintenant on traite les infos
|
|
|
|
// -- cas où à l'issue du calcul, racines est très proche de 1 ---
|
|
// dans ce cas on considère que la coïncidence est exacte
|
|
if (Dabs((1.-racine2)* delta_MPr_tatdt) <= tol_coincidence_reelle)
|
|
{ // on est dans le cas où l'on a une coïncidence exacte à la précision "tolerance_coincidence" près
|
|
// mais dans tous les cas on a rayon_tdt > Q_OiaR sinon on n'aurait pas de coïncidence
|
|
// on signale qu'il y a une coincidence exacte (pour le retour de la méthode Coincidence)
|
|
// gestion des pointeurs
|
|
Gestion_pointeur_coincidence(unSur_wprimeCarre,save_resul,W_a
|
|
,aucun_pt_inversion
|
|
,iatens,iafct,pt_sur_principal
|
|
,iatens_princ,iafct_princ,MPr_tdt);
|
|
return true;
|
|
};
|
|
|
|
// calcul de la valeur de sigma au point de coincidence, qui servira pour un nouveau calcul
|
|
MPr_i___ += racine2 * delta_MPr_tatdt;
|
|
// calcul du reste d'incrément de déformation qu'il faut utiliser pour la suite
|
|
delta_V *= (1.-racine2);
|
|
|
|
// mise à jour des différents pointeurs
|
|
Gestion_pointeur_coincidence(unSur_wprimeCarre,save_resul,W_a
|
|
,aucun_pt_inversion
|
|
,iatens,iafct,pt_sur_principal
|
|
,iatens_princ,iafct_princ,MPr_tdt);
|
|
|
|
// fin et retour, comme le calcul n'est pas fini on retourne false
|
|
return false;
|
|
};
|
|
|
|
// cas particulier d'une inversion et coïncidence : affinage d'un point de coincidence
|
|
// ramène true si le traitement est exactement terminé, sinon false, ce qui signifie qu'il
|
|
// faut encore continuer à utiliser l'équation d'évolution
|
|
// premiere_charge : indique si c'est oui ou non une coincidence avec la première charge
|
|
// pt_sur_principal : indique si oui ou non les pointeurs iafct et iatens pointent sur les listes
|
|
// principales
|
|
// iatens_princ et iafct_princ: pointeurs sur les listes principales
|
|
bool Hysteresis_bulk::Inversion_et_Coincidence(bool & aucun_pt_inversion,double& unSur_wprimeCarre
|
|
,SaveResulHysteresis_bulk & save_resul,double& W_a
|
|
,List_io <double>::iterator& iatens,const double& delta_MPr_tatdt
|
|
,List_io <double>::iterator& iafct
|
|
,bool& pt_sur_principal,List_io <double>::iterator& iatens_princ
|
|
,List_io <double>::iterator& iafct_princ
|
|
,double& delta_W_a,bool force_coincidence,const double& MPr_tdt)
|
|
{
|
|
// on se trouve dans un cas où la fonction d'aide ne peut pas être utilisée car ses valeurs actuelles
|
|
// n'ont pas pris en compte l'inversion -> du coup on va uniquement travailler avec les pressions
|
|
// tout d'abord on vérifie que l'on n'est pas exactement à un point de
|
|
// coincidence à la précision près
|
|
|
|
double tol_coincidence_reelle = tolerance_coincidence;
|
|
if (tolerance_coincidence < 0) // si l'indication est négative , cela veut dire que l'on veut une grandeur relative
|
|
tol_coincidence_reelle = MaX(-tolerance_coincidence * MPr_tdt,-tolerance_coincidence);
|
|
|
|
if ((Abs(delta_MPr_Ratdt) <= tol_coincidence_reelle) || force_coincidence)
|
|
{// on est dans le cas où l'on a une coïncidence exacte à la précision "tolerance_coincidence" près
|
|
// mais dans tous les cas on a rayon_tdt > Q_OiaR sinon on n'aurait pas de coïncidence
|
|
// on signale qu'il y a une coincidence exacte (pour le retour de la méthode Coincidence)
|
|
// gestion des pointeurs
|
|
Gestion_pointeur_Inversion_et_Coincidence(unSur_wprimeCarre,save_resul,W_a
|
|
,aucun_pt_inversion
|
|
,iatens,iafct,pt_sur_principal
|
|
,iatens_princ,iafct_princ,MPr_tdt);
|
|
return true;
|
|
};
|
|
// --- sinon on continue mais le traitement ne sera pas fini !!
|
|
|
|
// dans une première étape on tente de calculer plus précisemment le point de coïncidence,
|
|
// en supposant une approximation linéaire de l'évolution de la pression sur le pas de temps:
|
|
// on va donc séparer la variation de V en fct de la position du pt d'inversion
|
|
double ratio = Dabs(delta_MPr_Rat / delta_MPr_tatdt);
|
|
|
|
// calcul de la valeur de sigma au point de coincidence, qui servira pour un nouveau calcul
|
|
// première solution MPr_i___ += ratio * delta_MPr_tatdt;
|
|
// mais en fait comme on a ici une fonction à une variable, on doit retomber exactement sur la valeur
|
|
// de référence donc on prend cette valeur
|
|
MPr_i___ = MPr_R;
|
|
// calcul du reste d'incrément de déformation qu'il faut utiliser pour la suite
|
|
delta_V *= (1.-ratio);
|
|
|
|
// mise à jour des différents pointeurs
|
|
Gestion_pointeur_Inversion_et_Coincidence(unSur_wprimeCarre,save_resul,W_a
|
|
,aucun_pt_inversion
|
|
,iatens,iafct,pt_sur_principal
|
|
,iatens_princ,iafct_princ,MPr_tdt);
|
|
|
|
// fin et retour, comme le calcul n'est pas fini on retourne false
|
|
return false;
|
|
};
|
|
|
|
// gestion d'un dépilement des pointeurs dans les listes, dans le cas d'une coïncidence
|
|
// met à jour les booléens interne à l'instance : aucun_pt_inversion
|
|
void Hysteresis_bulk::Gestion_pointeur_coincidence(double& unSur_wprimeCarre
|
|
,SaveResulHysteresis_bulk & save_resul,double& W_a
|
|
,bool & aucun_pt_inversion
|
|
,List_io <double>::iterator& iatens
|
|
,List_io <double>::iterator& iafct
|
|
,bool& pt_sur_principal
|
|
,List_io <double>::iterator& iatens_princ
|
|
,List_io <double>::iterator& iafct_princ
|
|
,const double& MPr_tdt)
|
|
|
|
{
|
|
|
|
// 1-- cas de pt de ref: si on pointe sur la liste secondaire on retire les 2 derniers éléments
|
|
// sauf si on change de sens, dans ce cas il faut dépiler uniquement de 1
|
|
if (!pt_sur_principal)
|
|
{
|
|
if (iatens != save_resul.MPr_R_t_a_tdt.begin())
|
|
{ if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (abs(Permet_affichage()) > 0 ))
|
|
cout << "\n incoherence, on devrait avoir ici le premier element de la liste secondaire"
|
|
<< " des Mpr d'inversion"
|
|
<< "\n Hysteresis_bulk::Gestion_pointeur_coïncidence(..."<< endl;
|
|
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 4)) || (abs(Permet_affichage()) > 4))
|
|
Affiche_debug(unSur_wprimeCarre,save_resul,iatens,pt_sur_principal
|
|
,iatens_princ);
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();
|
|
};
|
|
|
|
// comme on est sur la liste secondaire, cela signifie qu'elle n'est pas vide en point d'inversion
|
|
// soit on a au moins 2 pt d'inversion, là on peut fermer une boucle
|
|
// sinon on peut également être dans le cas où on est passer de l'autre coté, c-a-d que l'on a rejoint
|
|
// la courbe de première charge dans l'autre sens
|
|
|
|
bool moitie_depiler=false; // sert pour un dépilage 1/2 (voir utilisation après)
|
|
|
|
if (save_resul.MPr_R_t_a_tdt.size() >= 2)
|
|
{// on supprime les éléments inutiles
|
|
save_resul.MPr_R_t_a_tdt.erase(save_resul.MPr_R_t_a_tdt.begin());
|
|
save_resul.MPr_R_t_a_tdt.erase(save_resul.MPr_R_t_a_tdt.begin());
|
|
// idem pour la fonction d'aide
|
|
save_resul.fct_aide_t_a_tdt.erase(save_resul.fct_aide_t_a_tdt.begin());
|
|
// on récupère la valeur exacte de la fonction d'aide
|
|
W_a = *(save_resul.fct_aide_t_a_tdt.begin()); // on met la vrai valeur sans approx
|
|
// on dépile pour avoir la nouvelle limite de la fonction d'aide
|
|
save_resul.fct_aide_t_a_tdt.erase(save_resul.fct_aide_t_a_tdt.begin());
|
|
}
|
|
else // sinon on est dans le cas d'une première inversion donc on regarde si on n'est pas passer
|
|
// de l'autre coté, c-a-d que l'on a rejoint la courbe de première charge dans l'autre sens
|
|
{double MPr_a_l_inversion = *(save_resul.MPr_R_t_a_tdt.begin()); // la -pression à l'inversion
|
|
if (MPr_tdt * MPr_a_l_inversion < 0.) // si négatif, on est passé de l'autre coté, c'est ok
|
|
{// on supprime les éléments inutiles, mais ici il n'y a qu'un seul point
|
|
//save_resul.MPr_R_t_a_tdt.erase(save_resul.MPr_R_t_a_tdt.begin()); // donc elle est vide
|
|
save_resul.MPr_R_t_a_tdt.clear(); // même ordre que précédemment mais plus clair
|
|
// on récupère la valeur exacte de la fonction d'aide
|
|
W_a = *(save_resul.fct_aide_t_a_tdt.begin()); // on met la vraie valeur sans approx
|
|
// on dépile pour avoir la nouvelle limite de la fonction d'aide
|
|
//save_resul.fct_aide_t_a_tdt.erase(save_resul.fct_aide_t_a_tdt.begin());
|
|
save_resul.fct_aide_t_a_tdt.clear(); // plus clair
|
|
}
|
|
else // sinon là il y a un pb
|
|
{if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (abs(Permet_affichage()) > 3 ))
|
|
cout << "\n warning il semble que l'on ait une inversion sur liste secondaire puis "
|
|
<< " coïncidence avec liste principale avec "
|
|
<< "\n Hysteresis_bulk::Gestion_pointeur_coïncidence(..."
|
|
<< endl;
|
|
// cout << "\n incoherence, on devrait avoir au moins 2 element de la liste secondaire"
|
|
// << " des Mpr d'inversion or on en a: "<< save_resul.MPr_R_t_a_tdt.size()
|
|
// << ", une raison possible est la valeur de la precision de coincidence qui fait qu'apres une seule"
|
|
// << " inversion on a tout de suite une coincidence (-> diminuer la tolerance de coincidence ?)"
|
|
// << "\n fct_aide= "<<W_a << ", a comparer avec fct_aide_ref= "<<*iafct
|
|
// << "\n Hysteresis_bulk::Gestion_pointeur_coïncidence(..."
|
|
// << endl;
|
|
////--- debug ---
|
|
//#ifdef MISE_AU_POINT
|
|
//cout << "\n debug Hysteresis_bulk::Gestion_pointeur_coincidence( ";
|
|
//throw ErrNonConvergence_loiDeComportement();
|
|
//#endif
|
|
////----- fin debug ----
|
|
// --- on suppose que c'est un pb de précision et on dépile une seule fois pour une coincidence
|
|
// approximativement correct -> auparavant on affichait le debug et on génèrait une exception ??
|
|
// avec la nouvelle méthode, on entèrine la coincidence et peut-être que l'on va faire du surplace
|
|
|
|
// on supprime les éléments inutiles, mais ici il n'y a qu'un seul point
|
|
save_resul.MPr_R_t_a_tdt.clear(); // même ordre que précédemment mais plus clair
|
|
// on récupère la valeur exacte de la fonction d'aide
|
|
W_a = *(save_resul.fct_aide_t_a_tdt.begin()); // on met la vraie valeur sans approx
|
|
// on dépile pour avoir la nouvelle limite de la fonction d'aide
|
|
//save_resul.fct_aide_t_a_tdt.erase(save_resul.fct_aide_t_a_tdt.begin());
|
|
save_resul.fct_aide_t_a_tdt.clear(); // plus clair
|
|
|
|
// if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 4)) || (abs(Permet_affichage()) > 4))
|
|
// Affiche_debug(unSur_wprimeCarre,save_resul,iatens,pt_sur_principal
|
|
// ,iatens_princ);
|
|
// // on génère une exception
|
|
// throw ErrNonConvergence_loiDeComportement();
|
|
|
|
// je pense que cela veut dire également que l'on doit dépiler une fois en plus sur la liste principale
|
|
// car en fait on vient de rattraper la liste à la précision de la fonction d'aide du coup la coïncidence
|
|
// est avec la liste principale
|
|
moitie_depiler = true;
|
|
};
|
|
};
|
|
|
|
if (save_resul.MPr_R_t_a_tdt.size()==0)
|
|
{// il ne reste plus d'élément on revient sur la liste principal
|
|
pt_sur_principal = true;
|
|
List_io <double>::iterator posi0=save_resul.MPr_R.end();
|
|
posi0--;
|
|
// on initialise les pointeurs courants sur les valeurs de la liste principale
|
|
iatens = iatens_princ;iafct=iafct_princ;
|
|
if (moitie_depiler) // cas d'un dépilage qui n'est pas fini c'est à dire en fait d'une
|
|
// coïncidence avec la liste principale: on dépile une fois si c'est possible
|
|
{ if (iatens != posi0) // cela veut dire que l'on est pas sur la première charge
|
|
{iatens++;
|
|
// contrairement au point de ref, la fonction d'aide est a dépiler qu'une fois
|
|
// car la valeur en cours vient de rattraper la précédente qui donc doit-être annulée
|
|
// et on revient sur celle d'avant
|
|
iafct++; //
|
|
// #ifdef MISE_AU_POINT
|
|
// double W_a_save = W_a; // sauvegarde pour pouvoir l'afficher
|
|
// #endif
|
|
W_a = *iafct; // on met la vrai valeur sans approx
|
|
save_resul.indic_coin.push_back(1); // un seul dépilage à faire
|
|
save_resul.nb_coincidence++; // on acte la coïncidence
|
|
// comme on est sur la liste principale, on met à jour les pointeurs de la liste principale
|
|
// parce que l'on a dépilé 1 fois sur la liste principale
|
|
iatens_princ = iatens;iafct_princ = iafct;
|
|
}
|
|
};
|
|
// on regarde si le pointeur est valide
|
|
// on regarde si le pointeur est valide
|
|
// on récupère la position de la valeur par défaut
|
|
if (iatens != posi0) {aucun_pt_inversion = false;}
|
|
else {aucun_pt_inversion = true;};
|
|
}
|
|
else // cas où il reste des éléments sur les listes secondaires
|
|
{iatens = save_resul.MPr_R_t_a_tdt.begin();aucun_pt_inversion = false;
|
|
iafct = save_resul.fct_aide_t_a_tdt.begin();
|
|
};
|
|
}
|
|
else // cas où on pointe sur la liste principal, on se déplace dans la liste principal,
|
|
// de deux en deux, normalement sauf si on change de sens
|
|
{ // sans éliminer d'élément : on update le pointage
|
|
// on récupère la position de la valeur par défaut des pt d'inversion
|
|
List_io <double>::iterator posi0=save_resul.MPr_R.end();
|
|
posi0--;//posi0--;
|
|
// if (iatens != save_resul.MPr_R.end())
|
|
// -- on regarde tout d'abord si on n'a pas changé de sens
|
|
|
|
// récup de la -pression d'inversion la plus grande sur la courbe de première charge
|
|
double MPr_a_l_inversion = *(save_resul.MPr_R.begin()); //(*posi0);
|
|
List_io <double>::iterator posi1 = iatens; posi1++; // posi1 c'est la future contrainte
|
|
List_io <double>::iterator iafact_posi0=save_resul.fct_aide.end(); iafact_posi0--;
|
|
List_io <double>::iterator iafact_posi1 = iafct; iafact_posi1++;
|
|
|
|
if ((MPr_tdt * MPr_a_l_inversion < 0.)
|
|
&& (((iatens != posi0) // cela veut dire que l'on était pas sur la première charge
|
|
&& (posi1 == posi0) // permet de vérifier que l'on vient bien de rattraper la courbe de 1ière
|
|
&& (iafact_posi1 == iafact_posi0))
|
|
) )
|
|
// si négatif, on est passé de l'autre coté, c'est ok
|
|
// par contre il faut dépiler uniquement qu'une fois si on a une qu'une seule inversion
|
|
// Dans le cas où on a plusieurs inversions enregistrées, il faut d'abord dépiler jusqu'à
|
|
// la première non infinie, pour ensuite calculer correctement le retour sur la branche principale
|
|
// dans la direction inverse. C'est notament le cas, quand le pas est beaucoup plus grand que
|
|
// les boucles enregistrées
|
|
//
|
|
{ // normalement cela veut dire que l'on vient de rattraper la courbe principale dans l'autre sens
|
|
// 1) cas où on revient dans la configuration originale
|
|
// if ((iatens != posi0) // cela veut dire que l'on était pas sur la première charge
|
|
// && (posi1 == posi0) // permet de vérifier que l'on vient bien de rattraper la courbe de 1ière
|
|
// && (iafact_posi1 == iafact_posi0))
|
|
{iatens=posi0;aucun_pt_inversion = true;
|
|
// idem pour iafct qui suivent une même logique: on doit avoir rattraper la valeur initiale
|
|
iafct=iafact_posi0;
|
|
W_a = *iafct; // on met la valeur initiale
|
|
save_resul.nb_coincidence++; // on acte la coïncidence
|
|
save_resul.indic_coin.push_back(1); // signale la coincidence avec un seul dépilage
|
|
// comme on est sur la liste principale, on met à jour les pointeurs de la liste principale
|
|
iatens_princ = iatens;iafct_princ = iafct;
|
|
}
|
|
// else // sinon il y a un pb car comme c'est une coïncidence il devrait rester un pointeur valide
|
|
// {if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (abs(Permet_affichage()) > 0))
|
|
// {cout << "\n incoherence, tout ce passe comme si on changeait de sens sur la courbe principale mais: ";
|
|
// if (iatens == posi0)
|
|
// cout << " \n on est deja sur la courbe principale !! ";
|
|
// if (posi1 != posi0)
|
|
// cout << " \n concernant les contraintes: on n'est pas sur la premiere courbe d'inversion !! ";
|
|
// if (iafact_posi1 == iafact_posi0)
|
|
// cout << " \n concernant la fonction d'aide: on n'est pas sur la premiere courbe d'inversion !! ";
|
|
// cout << "\n Hysteresis_bulk::Gestion_pointeur_coincidence(..." << endl;
|
|
// };
|
|
// if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 4)) || (abs(Permet_affichage()) > 4))
|
|
// Affiche_debug(unSur_wprimeCarre,save_resul,iatens,pt_sur_principal
|
|
// ,iatens_princ);
|
|
// // on génère une exception
|
|
// throw ErrNonConvergence_loiDeComportement();
|
|
// };
|
|
}
|
|
else // sinon on est dans un cas où on reste du même coté définitivement
|
|
// ou transitoirement le temps de rattraper la dernière inversion
|
|
// donc il faut dépiler 2 fois
|
|
{
|
|
if (iatens != posi0) // cela veut dire que l'on est pas sur la première charge
|
|
{iatens++;
|
|
// contrairement au point de ref, la fonction d'aide est a dépiler qu'une fois
|
|
// car la valeur en cours vient de rattraper la précédente qui donc doit-être annulée
|
|
// et on revient sur celle d'avant
|
|
iafct++; //
|
|
#ifdef MISE_AU_POINT
|
|
double W_a_save = W_a; // sauvegarde pour pouvoir l'afficher
|
|
#endif
|
|
W_a = *iafct; // on met la vrai valeur sans approx
|
|
if (iatens == posi0)
|
|
{ if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (abs(Permet_affichage()) > 0 ))
|
|
cout << "\n warning: Hysteresis_bulk::Gestion_pointeur_coincidence(.."
|
|
<< " on cherche a appliquer deux depilages, alors qu'un seul n'est possible !! "
|
|
<< " peut-etre un probleme de precision de la coincidence (diminuer la tolerance ?) ";
|
|
// #ifdef MISE_AU_POINT
|
|
// cout << "\n debug Hysteresis_bulk::Gestion_pointeur_coincidence( "
|
|
// << " W_a= "<<W_a_save
|
|
// << " *afct= "<< *iafct << endl;
|
|
// throw ErrNonConvergence_loiDeComportement(); // pour le débug
|
|
// #endif
|
|
cout << endl ;
|
|
|
|
// on est revenu sur la courbe de première en une fois, on remet tout ok
|
|
aucun_pt_inversion = true;
|
|
save_resul.indic_coin.push_back(1);
|
|
}
|
|
else // sinon cas normal de deux dépilages
|
|
{iatens++;// idem pour iafct qui suivent une même logique
|
|
// mais il faut mettre à jour la fonction d'aide par rapport à la valeur
|
|
// qu'elle avait au point d'inversion précédent sinon, c'est perdue
|
|
|
|
iafct++; // puis on se repositionne pour les prochains tests de coïncidence
|
|
// on regarde si le pointeur est valide
|
|
if (iatens != posi0) {aucun_pt_inversion = false;}
|
|
else {aucun_pt_inversion = true;};
|
|
save_resul.indic_coin.push_back(2); // signale la coincidence avec deux dépilages
|
|
|
|
};
|
|
save_resul.nb_coincidence++; // on acte la coïncidence
|
|
// comme on est sur la liste principale, on met à jour les pointeurs de la liste principale
|
|
iatens_princ = iatens;iafct_princ = iafct;
|
|
}
|
|
else // sinon il y a un pb car comme c'est une coïncidence il devrait rester un pointeur valide
|
|
{if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (abs(Permet_affichage()) > 0))
|
|
cout << "\n incoherence, il devrait rester un pointeur de valide sur la liste de pt de ref"
|
|
<< "\n Hysteresis_bulk::Gestion_pointeur_coincidence(..." << endl;
|
|
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 4)) || (abs(Permet_affichage()) > 4))
|
|
Affiche_debug(unSur_wprimeCarre,save_resul,iatens,pt_sur_principal
|
|
,iatens_princ);
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();
|
|
};
|
|
};
|
|
};
|
|
|
|
// 3-- traitement particulier dans le cas où on a rejoint la première charge
|
|
if (aucun_pt_inversion) // cas où l'on est sur la courbe de première charge
|
|
{ wprime = 1; unSur_wprimeCarre = 1./(wprime*wprime);
|
|
W_a = *save_resul.ip2; // on récupère la valeur de la fct d'aide au deuxième
|
|
iafct = save_resul.ip2;
|
|
}
|
|
else
|
|
// on met à jour en indiquant que l'on a rattrapé une courbe
|
|
{//W_a = *iafct;
|
|
wprime = 2; unSur_wprimeCarre = 1./(wprime*wprime);
|
|
};
|
|
|
|
// gestion du paramètre "modif" de saveresult
|
|
bool inversion = false;
|
|
Gestion_para_Saveresult_Modif(pt_sur_principal,save_resul,inversion);
|
|
|
|
//--------débug- traçage
|
|
#ifdef MISE_AU_POINT
|
|
if (Permet_affichage() == -77)
|
|
{ cout << "\ngestion de pointeur de coïncidence ";
|
|
cout << " aucun_pt_inversion= " << aucun_pt_inversion
|
|
<< " save_resul.nb_coincidence= " << save_resul.nb_coincidence;
|
|
cout << " \nsigR_sur_principal= " << pt_sur_principal
|
|
<< " save_resul.modif= " << save_resul.modif
|
|
<< " nb_sigR= "<<save_resul.MPr_R.size()
|
|
<< " nb_sigR_sec= " << save_resul.MPr_R_t_a_tdt.size()
|
|
<< " || wprime= " << wprime
|
|
<< endl ;
|
|
};
|
|
#endif
|
|
//----- fin débug
|
|
|
|
|
|
};
|
|
|
|
|
|
// gestion d'un dépilement des pointeurs dans les listes, dans le cas particulier
|
|
// d'une inversion - coïncidence (dans un même pas !!)
|
|
// met à jour les booléens interne à l'instance : aucun_pt_inversion
|
|
void Hysteresis_bulk::Gestion_pointeur_Inversion_et_Coincidence(double& unSur_wprimeCarre
|
|
,SaveResulHysteresis_bulk & save_resul,double& W_a
|
|
,bool & aucun_pt_inversion
|
|
,List_io <double>::iterator& iatens
|
|
,List_io <double>::iterator& iafct
|
|
,bool& pt_sur_principal
|
|
,List_io <double>::iterator& iatens_princ
|
|
,List_io <double>::iterator& iafct_princ
|
|
,const double& MPr_tdt)
|
|
|
|
{
|
|
|
|
// 1-- cas de pt de ref: si on pointe sur la liste secondaire on retire le dernier élément
|
|
// ==> on dépile de 1
|
|
bool fin_de_traitement_a_faire = true; //init: sert pour discriminer le cas très particulier
|
|
// du démarrage avec rien d'enregistré
|
|
if (!pt_sur_principal)
|
|
{
|
|
if (iatens != save_resul.MPr_R_t_a_tdt.begin())
|
|
{ if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (abs(Permet_affichage()) > 0 ))
|
|
cout << "\n incoherence, on devrait avoir ici le premier element de la liste secondaire"
|
|
<< " des Mpr d'inversion"
|
|
<< "\n Hysteresis_bulk::Gestion_pointeur_Inversion_et_Coincidence(..."<< endl;
|
|
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 4)) || (abs(Permet_affichage()) > 4))
|
|
Affiche_debug(unSur_wprimeCarre,save_resul,iatens,pt_sur_principal
|
|
,iatens_princ);
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();
|
|
};
|
|
|
|
// comme on est sur la liste secondaire, cela signifie qu'elle n'est pas vide en point d'inversion
|
|
// on a au moins 1 pt d'inversion, là on peut fermer une boucle
|
|
// Important: le cas où on est passer de l'autre coté, c-a-d que l'on a rejoint
|
|
// la courbe de première charge dans l'autre sens, n'est pas prévu et n'est pas normal a priori
|
|
// --> message d'erreur
|
|
|
|
// on commence par vérifier que l'on n'est pas passé de l'autre coté
|
|
{double MPr_a_l_inversion = *(save_resul.MPr_R_t_a_tdt.begin()); // la -pression à l'inversion
|
|
if (MPr_tdt * MPr_a_l_inversion < 0.) // si négatif, on est passé de l'autre coté, ce n'est pas normal
|
|
// on met un message d'erreur
|
|
{if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (abs(Permet_affichage()) > 0))
|
|
cout << "\n incoherence sur la liste secondaire, on a change de sens au niveau de la coincidence or "
|
|
<< " ce cas n'est pas prevu lors d'une inversion-coincidence !! "
|
|
<< "\n Hysteresis_bulk::Gestion_pointeur_Inversion_et_Coincidence(..." << endl;
|
|
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 4)) || (abs(Permet_affichage()) > 4))
|
|
Affiche_debug(unSur_wprimeCarre,save_resul,iatens,pt_sur_principal
|
|
,iatens_princ);
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();
|
|
};
|
|
};
|
|
|
|
// --- maintenant on dépile une fois
|
|
// on supprime les éléments inutiles
|
|
save_resul.MPr_R_t_a_tdt.erase(save_resul.MPr_R_t_a_tdt.begin());
|
|
// idem pour la fonction d'aide
|
|
// on récupère la valeur exacte de la fonction d'aide
|
|
W_a = *(save_resul.fct_aide_t_a_tdt.begin()); // on met la vrai valeur sans approx
|
|
// on dépile pour avoir la nouvelle limite de la fonction d'aide
|
|
save_resul.fct_aide_t_a_tdt.erase(save_resul.fct_aide_t_a_tdt.begin());
|
|
|
|
// on regarde s'il ne faut pas revenir sur la liste principal
|
|
if (save_resul.MPr_R_t_a_tdt.size()==0)
|
|
{// il ne reste plus d'élément on revient sur la liste principal
|
|
pt_sur_principal = true;
|
|
iatens = iatens_princ; iafct=iafct_princ;
|
|
// on regarde si le pointeur est valide
|
|
// on récupère la position de la valeur par défaut
|
|
List_io <double>::iterator posi0=save_resul.MPr_R.end(); posi0--;
|
|
if (iatens != posi0) {aucun_pt_inversion = false;}
|
|
else {aucun_pt_inversion = true;};
|
|
}
|
|
else // cas où il reste des éléments sur les listes secondaires
|
|
{iatens = save_resul.MPr_R_t_a_tdt.begin();aucun_pt_inversion = false;
|
|
iafct = save_resul.fct_aide_t_a_tdt.begin();
|
|
};
|
|
}
|
|
else if (save_resul.MPr_R.size() == 1)
|
|
// cas où on pointe sur la liste principal, mais en fait on n'a pas enregistré de nouveau pt de ref
|
|
// c'est le cas au début du chargement par exemple, donc ici on ne peut pas supprimer de point !
|
|
{ // comme on est repassé par l'origine, il faut remettre à 0 wa
|
|
// et s'il y a un morceau encore de calcul, le wa sera updaté du morceau restant
|
|
W_a = 0.; // le point de coïncidence c'est en fait l'origine
|
|
// à part cela, il n'y a rien n'a faire, car pour l'instant il n'y a rien d'enregistré dans les listes
|
|
// donc les pointeurs ne sont pas à changer
|
|
fin_de_traitement_a_faire = false; // on indique que c'est fini
|
|
}
|
|
else // cas où on pointe sur la liste principal,
|
|
{ // on se déplace dans la liste principal de 1, sans éliminer d'élément : on update le pointage
|
|
// on récupère la position de la valeur par défaut des pt d'inversion
|
|
List_io <double>::iterator posi0=save_resul.MPr_R.end();
|
|
posi0--;
|
|
|
|
// -- on regarde tout d'abord si on n'a pas changé de sens
|
|
// ce cas normalement n'est pas prévu dans le cas d'une inversion-coïncidence donc
|
|
// on met un message d'erreur
|
|
|
|
// récup de la -pression d'inversion la plus grande sur la courbe de première charge
|
|
double MPr_a_l_inversion = *(save_resul.MPr_R.begin()); //(*posi0);
|
|
List_io <double>::iterator posi1 = iatens; posi1++; // posi1 c'est la future contrainte
|
|
List_io <double>::iterator iafact_posi0=save_resul.fct_aide.end(); iafact_posi0--;
|
|
List_io <double>::iterator iafact_posi1 = iafct; iafact_posi1++;
|
|
|
|
if ((MPr_tdt * MPr_a_l_inversion < 0.)
|
|
&& (((iatens != posi0) // cela veut dire que l'on était pas sur la première charge
|
|
&& (posi1 == posi0) // permet de vérifier que l'on vient bien de rattraper la courbe de 1ière
|
|
&& (iafact_posi1 == iafact_posi0))
|
|
) )
|
|
// si négatif, on est passé de l'autre coté,
|
|
{if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (abs(Permet_affichage()) > 0))
|
|
cout << "\n incoherence sur la liste principale, on a change de sens au niveau de la coincidence or "
|
|
<< " ce cas n'est pas prevu lors d'une inversion-coincidence !! "
|
|
<< "\n Hysteresis_bulk::Gestion_pointeur_Inversion_et_Coincidence(..." << endl;
|
|
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 4)) || (abs(Permet_affichage()) > 4))
|
|
Affiche_debug(unSur_wprimeCarre,save_resul,iatens,pt_sur_principal
|
|
,iatens_princ);
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();
|
|
}
|
|
else // sinon on est dans un cas où on reste du même coté définitivement
|
|
// ou transitoirement le temps de rattraper la dernière inversion
|
|
// donc il faut dépiler 1 fois
|
|
{
|
|
if (iatens != posi0) // cela veut dire que l'on est pas sur la première charge
|
|
{iatens++;
|
|
W_a = *iafct; // on met la vrai valeur sans approx : 10 nov 2017
|
|
iafct++; //
|
|
// W_a = *iafct; // on met la vrai valeur sans approx : 10 nov 2017
|
|
|
|
if (iatens != posi0) {aucun_pt_inversion = false;}
|
|
else {aucun_pt_inversion = true;};
|
|
save_resul.indic_coin.push_back(1); // un seul dépilage
|
|
save_resul.nb_coincidence++; // on acte la coïncidence
|
|
// comme on est sur la liste principale, on met à jour les pointeurs de la liste principale
|
|
iatens_princ = iatens;iafct_princ = iafct;
|
|
}
|
|
else // sinon il y a un pb car comme c'est une coïncidence il devrait rester un pointeur valide
|
|
{if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (abs(Permet_affichage()) > 0))
|
|
cout << "\n incoherence, il devrait rester un pointeur de valide sur la liste de pt de ref"
|
|
<< "\n Hysteresis_bulk::Gestion_pointeur_Inversion_et_Coincidence(..." << endl;
|
|
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 4)) || (abs(Permet_affichage()) > 4))
|
|
Affiche_debug(unSur_wprimeCarre,save_resul,iatens,pt_sur_principal
|
|
,iatens_princ);
|
|
// on génère une exception
|
|
throw ErrNonConvergence_loiDeComportement();
|
|
};
|
|
};
|
|
};
|
|
|
|
if (fin_de_traitement_a_faire)
|
|
{// 3-- traitement particulier dans le cas où on a rejoint la première charge
|
|
if (aucun_pt_inversion) // cas où l'on est sur la courbe de première charge
|
|
{ wprime = 1; unSur_wprimeCarre = 1./(wprime*wprime);
|
|
W_a = *save_resul.ip2; // on récupère la valeur de la fct d'aide au deuxième
|
|
iafct = save_resul.ip2;
|
|
}
|
|
else
|
|
// on met à jour en indiquant que l'on a rattrapé une courbe
|
|
{wprime = 2; unSur_wprimeCarre = 1./(wprime*wprime);
|
|
};
|
|
|
|
// gestion du paramètre "modif" de saveresult
|
|
bool inversion = false;
|
|
Gestion_para_Saveresult_Modif(pt_sur_principal,save_resul,inversion);
|
|
};
|
|
|
|
//--------débug- traçage
|
|
#ifdef MISE_AU_POINT
|
|
if (Permet_affichage() == -77)
|
|
{ cout << "\ngestion de pointeur de coïncidence: cas particulier d'une inversion - coincidence ";
|
|
cout << " aucun_pt_inversion= " << aucun_pt_inversion
|
|
<< " save_resul.nb_coincidence= " << save_resul.nb_coincidence;
|
|
cout << " \nsigR_sur_principal= " << pt_sur_principal
|
|
<< " save_resul.modif= " << save_resul.modif
|
|
<< " nb_sigR= "<<save_resul.MPr_R.size()
|
|
<< " nb_sigR_sec= " << save_resul.MPr_R_t_a_tdt.size()
|
|
<< " || wprime= " << wprime
|
|
<< endl ;
|
|
};
|
|
#endif
|
|
//----- fin débug
|
|
|
|
|
|
};
|
|
|
|
// gestion du paramètre "modif" de saveresult
|
|
// inversion = true: on met à jour après une inversion
|
|
// = false : on met à jour après une coïncidence
|
|
void Hysteresis_bulk::Gestion_para_Saveresult_Modif
|
|
(const bool& pt_sur_principal,SaveResulHysteresis_bulk & save_resul
|
|
,const bool& inversion
|
|
)
|
|
{
|
|
// --- gestion de l'indicateur modif
|
|
switch (save_resul.modif)
|
|
{ case 0: // le cas le plus simple: on avait rien avant
|
|
{if (inversion) save_resul.modif = 2; // cas d'une inversion
|
|
else save_resul.modif = 1; // cas d'une coïncidence
|
|
break;
|
|
}
|
|
case 1: // on a déjà une ou plusieurs coïncidence(s)
|
|
{if (inversion) save_resul.modif = 3; // cas d'une inversion
|
|
else save_resul.modif = 1; // cas d'une coïncidence
|
|
break;
|
|
}
|
|
case 2: // on avait une ou plusieurs inversions
|
|
{if (inversion) save_resul.modif = 2; // cas d'une inversion sup
|
|
else // cas d'une coïncidence
|
|
{if (pt_sur_principal) save_resul.modif = 0; // on est revenu sur la courbe principal
|
|
else save_resul.modif = 2; // il reste encore des pt secondaires
|
|
};
|
|
break;
|
|
}
|
|
case 3: // on avait un mixte d'inversion et de coïncidence
|
|
{if (inversion) save_resul.modif = 3; // cas d'une inversion sup
|
|
else // cas d'une coïncidence
|
|
{if (pt_sur_principal) save_resul.modif = 1; // on est revenu en coïncidence résiduelle
|
|
else save_resul.modif = 3; // il reste encore des pt secondaires
|
|
};
|
|
break;
|
|
}
|
|
default:
|
|
cout << "\n Erreur *** Hysteresis_bulk::Gestion_para_Saveresult_Modif: cas non prevu !!"
|
|
<< " erreur save_resul.modif= " << save_resul.modif << endl;
|
|
Sortie(1);
|
|
break;
|
|
};
|
|
};
|
|
|
|
// initialisation éventuelle des variables thermo-dépendantes
|
|
void Hysteresis_bulk::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_temperature->Valeur(*temperature);
|
|
if (Qzero_temperature != NULL) Qzero = Qzero_temperature->Valeur(*temperature);
|
|
if (xmu_temperature != NULL) xmu = xmu_temperature->Valeur(*temperature);
|
|
};
|
|
|
|
// calcul de l'avancement temporel sur 1 pas,
|
|
// utilisé par les 3 programmes principaux:
|
|
// Calcul_SigmaHH, Calcul_DsigmaHH_tdt, Calcul_dsigma_deps,
|
|
// void Hysteresis_bulk::Avancement_temporel(const Tenseur3BB & delta_epsBB,const Tenseur3HH & gijHH
|
|
// ,SaveResulHysteresis_bulk & save_resul
|
|
// ,Tenseur3HH & sigHH)
|
|
void Hysteresis_bulk::Avancement_temporel(const Tenseur3HH & gijHH
|
|
,const Tenseur3BB & gijBB,int cas,SaveResulHysteresis_bulk & save_resul
|
|
,Tenseur3HH & sigHH,const EnergieMeca & energ_t,EnergieMeca & energ)
|
|
{
|
|
// la pression initiale, 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,
|
|
// MPr_i___ variera, à chaque passage
|
|
MPr_i___ = save_resul.MPr_t;
|
|
save_resul.Init_debut_calcul(); // on initialise les listes intermédiaires
|
|
////--- debug ---
|
|
//#ifdef MISE_AU_POINT
|
|
// { cout << "\n debug Hysteresis_bulk::Avancement_temporel( "
|
|
// << " MPr_i___= "<< MPr_i___ << endl;
|
|
// };
|
|
//#endif
|
|
////----- fin debug ----
|
|
|
|
//récup et initialisation des variables de travail
|
|
// iatens_princ: pointeur sur la liste déjà enregistrée, iatens: pointeur courant
|
|
List_io <double>::iterator iatens_princ = save_resul.MPr_R.begin();
|
|
List_io <double>::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 !
|
|
// en fait MPr_R contient par défaut une première valeur = 0 donc on regarde s'il n'y a pas 2 valeurs
|
|
if (save_resul.MPr_R.size() > 1 )
|
|
aucun_pt_inversion = false; // cas où on a déjà des inversions
|
|
|
|
// un pointeur qui indique si les pointeurs courants sont sur les listes principales ou
|
|
// sur les nouvelles liste
|
|
bool pt_sur_principal = true;
|
|
int phase_coincidence = 0; // pour la gestion de la coincidence
|
|
bool premier_passage = true; // init
|
|
|
|
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
|
|
wprime = save_resul.wprime_t; // initialisation du paramètre de masing
|
|
double unSur_wprimeCarre= 1./(wprime*wprime);
|
|
// le delta_V initial a été calculé dans le programme principale
|
|
|
|
// 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$$$ === Hysteresis_bulk::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
|
|
|
|
// -- 1) MPr_R : initialisé sur la liste principal, mais ensuite peut évoluer sur liste secondaire
|
|
MPr_R = *iatens; // toujours vrai car on met une première valeur nulle
|
|
// if (aucun_pt_inversion) {MPr_R=0.;}
|
|
// else {MPr_R = *iatens;}; // la contrainte de référence
|
|
delta_MPr_Rat = MPr_i___ - MPr_R;
|
|
|
|
// le calcul de MPr s'effectue par la résolution de l'équation différentielle
|
|
// du schéma constitutif
|
|
// MPr_point = 2*mu*V_point + beta*phi*(delta_barre de t à R de MPr)
|
|
|
|
//--------débug- traçage
|
|
#ifdef MISE_AU_POINT
|
|
if (Permet_affichage() == -77)
|
|
{ cout << " \nMPr_R_sur_principal= " << pt_sur_principal
|
|
<< " save_resul.modif= " << save_resul.modif
|
|
<< " nb_MPr_R= "<<save_resul.MPr_R.size()
|
|
<< " || nb_fct_aide= " << save_resul.fct_aide.size()
|
|
<< " nb_MPr_R_sec= " << save_resul.MPr_R_t_a_tdt.size()
|
|
<< " || nb_fct_aide_sec= " << save_resul.fct_aide_t_a_tdt.size()
|
|
<< " || wprime= " << wprime
|
|
<< "\n pr_initiale "<<MPr_i___<<endl;
|
|
};
|
|
#endif
|
|
//----- fin débug
|
|
// méthode permettant le calcul de sigma à tdt par différente méthodes: linéarisation
|
|
// ou kutta
|
|
// en sortie calcul de :
|
|
// MPr_t___tdt, delta_MPr_tatdt
|
|
CalculPression_tdt(save_resul.indicateurs_resolution);
|
|
// après le calcul de la pression on peut éventuellement avoir dépassé le seuil
|
|
// par contre cela signifie que l'on a forcément une coïncidence ou que la contrainte
|
|
// à été calculée avec une erreur importante: il faut donc vérifier ces deux points
|
|
|
|
delta_MPr_Ratdt = MPr_t___tdt - MPr_R;
|
|
double delta_MPr_tatdt = delta_MPr_Ratdt - delta_MPr_Rat; // variation entre t et tdt
|
|
// 2==== gestion de la mémoire discrète
|
|
// double phi_1_dt = delta_MPr_Rat * delta_V;
|
|
double phi_1_dt = delta_MPr_Ratdt * delta_V;
|
|
|
|
//--------débug- traçage
|
|
#ifdef MISE_AU_POINT
|
|
if (Permet_affichage() == -77)
|
|
{ cout << "\nCalculPression_tdt(...";
|
|
cout << " MPr_t___tdt = " << setprecision(ParaGlob::NbdigdoEC())
|
|
<< MPr_t___tdt << " delta_MPr_Ratdt = "<< delta_MPr_Ratdt
|
|
<< " phi_1_dt= "<< phi_1_dt
|
|
<< endl ;
|
|
};
|
|
#endif
|
|
//----- fin débug
|
|
|
|
|
|
if (phi_1_dt<0.) // au lieu de (delta_W_a < 0.) : cf. thèse de Nicolas
|
|
// --- cas de la détection d'un point d'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)
|
|
|
|
// ---- pb
|
|
double phidt = delta_MPr_Ratdt * delta_V;
|
|
// dans l'expression suivante, on utilise la règle des trapèzes pour le calcul de l'incrément
|
|
// double delta_W_a_essai = (phi_1_dt + phidt) * unSur_wprimeCarre;
|
|
// double W_a_essai = delta_W_a_essai + W_a;
|
|
// // if (W_a > *iafct)
|
|
// if ((W_a_essai < *iafct)
|
|
// && (*iafct != ConstMath::tresgrand)
|
|
// )
|
|
// {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 inferieur 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_essai= " << W_a_essai << " iafct= " << *iafct;
|
|
//// //--- pour le debug
|
|
//// if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
|
|
//// save_resul.Affiche();
|
|
//// //--- fin debug
|
|
// cout << "\n Hysteresis_bulk::Avancement_temporel(..."
|
|
// << endl;
|
|
// Sortie(1);}
|
|
//
|
|
// -- fin pb
|
|
|
|
//--------débug- traçage
|
|
#ifdef MISE_AU_POINT
|
|
if (Permet_affichage() == -77)
|
|
{ cout << "\ninversion " << endl ;
|
|
};
|
|
#endif
|
|
//----- fin débug
|
|
|
|
// gestion du paramètre "modif" de saveresult
|
|
bool inversion = true;
|
|
Gestion_para_Saveresult_Modif(pt_sur_principal,save_resul,inversion);
|
|
|
|
save_resul.indic_coin.push_back(0); // signale l'inversion
|
|
|
|
// ajout de la contrainte de référence = sigma at, et du niveau de la fonction d'aide
|
|
save_resul.MPr_R_t_a_tdt.push_front(MPr_i___);
|
|
////--- debug ---
|
|
//#ifdef MISE_AU_POINT
|
|
// { cout << "\n debug Hysteresis_bulk::Avancement_temporel( "
|
|
// << " à la sauvegarde: MPr_i___= "<< MPr_i___ << endl;
|
|
// };
|
|
//#endif
|
|
////----- fin debug ----
|
|
save_resul.fct_aide_t_a_tdt.push_front(W_a);
|
|
iatens = save_resul.MPr_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
|
|
W_a=0.; delta_W_a = 0.; // on ré-initialise pour les futures coincidences éventuelles
|
|
aucun_pt_inversion = false; //modif 15 dec 2015
|
|
// on indique le point d'inversion pour les futurs traitements
|
|
MPr_R = save_resul.MPr_R_t_a_tdt.front();
|
|
// point d'inversion
|
|
save_resul.wprime_tdt = 2.;
|
|
wprime = 2.; unSur_wprimeCarre = 0.25;
|
|
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
|
|
}
|
|
else if ( (Dabs(delta_MPr_tatdt) > Dabs(delta_MPr_Rat)) // le nouvel accroissement dépasse la taille du R au pt précédent
|
|
&& (delta_MPr_Rat * delta_MPr_Ratdt < 0.) // les deux accroissements sont de sens différents
|
|
)
|
|
// cas où on fait une inversion et une coïncidence en même temps
|
|
{
|
|
fin_traitement = Inversion_et_Coincidence(aucun_pt_inversion,unSur_wprimeCarre
|
|
,save_resul
|
|
,W_a,iatens,delta_MPr_tatdt
|
|
,iafct,pt_sur_principal,iatens_princ
|
|
,iafct_princ,delta_W_a,false,MPr_t___tdt);
|
|
|
|
}
|
|
else if (!force_fin_traitement) // sinon (phi_1_dt >= 0.) donc pas a priori pas d'inversion
|
|
{
|
|
double phidt = delta_MPr_Ratdt * delta_V;
|
|
// dans l'expression suivante, on utilise la règle des trapèzes pour le calcul de l'incrément
|
|
delta_W_a = 0.5*(phi_1_dt + phidt) * unSur_wprimeCarre;
|
|
W_a += delta_W_a;
|
|
// il faut cependant considéré également le cas où on est très près de la saturation
|
|
// car dans ce cas les erreurs d'arrondi peuvent conduire à ne pas détecter correctement
|
|
// la coïncidence et à dépasser le seuil de saturation
|
|
// Pour cela on test directement la valeur de la contrainte
|
|
// bool depasse_saturation = false; // init
|
|
////--- debug ---
|
|
//#ifdef MISE_AU_POINT
|
|
// { cout << "\n debug Hysteresis_bulk::Avancement_temporel( "
|
|
// << " à la sauvegarde 1 : MPr_t___tdt= "<< MPr_t___tdt << endl;
|
|
// if (Abs(MPr_t___tdt) > Qzero)
|
|
// { cout << "\n pb "
|
|
// << " MPr_t___tdt= "<< MPr_t___tdt << endl;
|
|
// throw ErrNonConvergence_loiDeComportement();
|
|
// };
|
|
// };
|
|
//#endif
|
|
////----- fin debug ----
|
|
if (Dabs(delta_MPr_Ratdt) > wprime*Qzero)
|
|
// normalement on devrait trouver une coïncidence,
|
|
//on va donc forcer la coïncidence
|
|
{W_a = *iafct + ConstMath::trespetit;
|
|
// throw ErrNonConvergence_loiDeComportement();
|
|
};
|
|
// #ifdef MISE_AU_POINT
|
|
// cout << "\n debug Hysteresis_bulk::Avancement_temporel( "
|
|
// << " *afct= "<< *iafct << endl;
|
|
// #endif
|
|
|
|
|
|
if ((W_a <= *iafct) // cas normal après plusieurs inversion
|
|
|| (save_resul.fct_aide.size() == 1) || (wprime == 1.)) // cas de la courbe de première charge
|
|
{ // --- 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
|
|
// --- avant d'enregistrer on filtre si on a dépassé la saturation, ------
|
|
// sinon l'erreur va rester pour toute la suite du calcul
|
|
if (Dabs(MPr_t___tdt) > Qzero)
|
|
{if (((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3))
|
|
|| (abs(Permet_affichage()) > 3))
|
|
cout << "\n ** warning dans le calcul de la contrainte a t+dt, on trouve "
|
|
<< " une valeur de pression -P= (" << MPr_t___tdt
|
|
<< ") > a la saturation = "<< Qzero
|
|
<< "\n ->arbitrairement on limite a la saturation "
|
|
<< endl;
|
|
MPr_t___tdt = DSigne(MPr_t___tdt) * Qzero;
|
|
delta_MPr_Ratdt = MPr_t___tdt - MPr_R;
|
|
};
|
|
fin_traitement = true;
|
|
// la suite sera à supprimer, car on effectue tout à la fin
|
|
// save_resul.MPr_tdt = MPr_t___tdt;
|
|
// save_resul.fonction_aide_tdt = W_a;
|
|
// save_resul.wprime_tdt = wprime;
|
|
// // calcul de la contrainte de retour
|
|
// sigHH = gijHH * MPr_t___tdt;
|
|
}
|
|
else // sinon (W_a > save_resul.fct_aide.front()) -> coincidence
|
|
{ // et ici il y a forcément plus de 1 point d'inversion
|
|
if (W_a <= *(save_resul.ip2))
|
|
// if (W_a > *(save_resul.ip2))
|
|
{ // --- cas d'une coincidence quelconque ou sur première charge ---
|
|
fin_traitement = Coincidence(aucun_pt_inversion,unSur_wprimeCarre,false,save_resul,W_a,iatens
|
|
,iafct,pt_sur_principal,iatens_princ,iafct_princ,delta_W_a,false,MPr_t___tdt);
|
|
}
|
|
else // coincidence avec la courbe de première charge
|
|
{ fin_traitement = Coincidence(aucun_pt_inversion,unSur_wprimeCarre,true,save_resul,W_a,iatens
|
|
,iafct,pt_sur_principal,iatens_princ,iafct_princ,delta_W_a,false,MPr_t___tdt);
|
|
};
|
|
|
|
// la suite est commentée et devra être supprimée (si pas de pb) car le traitement est effectué uniquement une fois
|
|
// tout à la fin
|
|
// if (fin_traitement) // calcul de la contrainte de retour si le traitement est fini
|
|
// { // --- avant d'enregistrer on filtre si on a dépassé la saturation, ------
|
|
// // sinon l'erreur va rester pour toute la suite du calcul
|
|
// if (Dabs(MPr_t___tdt) > Qzero)
|
|
// {if (((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3))
|
|
// || (abs(Permet_affichage()) > 3))
|
|
// cout << "\n ** warning dans le calcul de la contrainte a t+dt, on trouve "
|
|
// << " une valeur de pression -P= (" << MPr_t___tdt
|
|
// << ") > a la saturation = "<< Qzero
|
|
// << "\n ->arbitrairement on limite a la saturation "
|
|
// << endl;
|
|
// MPr_t___tdt = DSigne(MPr_t___tdt) * Qzero;
|
|
// };
|
|
// sigHH = gijHH * MPr_t___tdt;
|
|
// save_resul.MPr_tdt = MPr_t___tdt;
|
|
//////--- debug ---
|
|
////#ifdef MISE_AU_POINT
|
|
//// { cout << "\n debug Hysteresis_bulk::Avancement_temporel( "
|
|
//// << " à la sauvegarde 2 : MPr_t___tdt= "<< MPr_t___tdt << endl;
|
|
//// };
|
|
////#endif
|
|
//////----- fin debug ----
|
|
// save_resul.fonction_aide_tdt = W_a;
|
|
// save_resul.wprime_tdt = wprime;
|
|
// };
|
|
//--------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
|
|
} // -- fin du else du if (phi_1_dt<0.) : évolution normale
|
|
} // -- fin du else du if (phi_1_dt<0.) : point d'inversion
|
|
else // cas où on force la fin du traitement: force_fin_traitement = true
|
|
{fin_traitement = true;
|
|
double phidt = delta_MPr_Ratdt * delta_V;
|
|
// dans l'expression suivante, on utilise la règle des trapèzes pour le calcul de l'incrément
|
|
delta_W_a = (phi_1_dt + phidt) * unSur_wprimeCarre;
|
|
W_a += delta_W_a;
|
|
// et ici il y a forcément plus de 1 point d'inversion
|
|
if (W_a <= *(save_resul.ip2))
|
|
{ // --- cas d'une coincidence quelconque ou sur première charge ---
|
|
Coincidence(aucun_pt_inversion,unSur_wprimeCarre,false,save_resul,W_a,iatens
|
|
,iafct,pt_sur_principal,iatens_princ,iafct_princ,delta_W_a,false,MPr_t___tdt);
|
|
// la suite est commentée et devra être supprimée (si pas de pb) car le traitement est effectué uniquement une fois
|
|
// tout à la fin
|
|
// // calcul de la contrainte de retour si le traitement est fini
|
|
// sigHH = gijHH * MPr_t___tdt;
|
|
}
|
|
else // coincidence avec la courbe de première charge
|
|
{ Coincidence(aucun_pt_inversion,unSur_wprimeCarre,true,save_resul,W_a,iatens
|
|
,iafct,pt_sur_principal,iatens_princ,iafct_princ,delta_W_a,false,MPr_t___tdt);
|
|
// la suite est commentée et devra être supprimée (si pas de pb) car le traitement est effectué uniquement une fois
|
|
// tout à la fin
|
|
// // calcul de la contrainte de retour si le traitement est fini
|
|
// sigHH = gijHH * MPr_t___tdt;
|
|
};
|
|
//--------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
|
|
};
|
|
|
|
// 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)) || (abs(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 << endl;
|
|
// si on est toujours sur la liste principale cela veut dire
|
|
// que l'on a créé une secondaire puis on la supprimé etc ... boucle infini
|
|
if (pt_sur_principal)
|
|
{ // 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)) || (abs(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)) || (abs(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)
|
|
|
|
// arrivée ici on considère que la contrainte calculée est correcte
|
|
// on calcul la contrainte de retour
|
|
// --- avant d'enregistrer on filtre si on a dépassé la saturation, ------
|
|
// sinon l'erreur va rester pour toute la suite du calcul
|
|
if (Dabs(MPr_t___tdt) > Qzero)
|
|
{if (((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3))
|
|
|| (abs(Permet_affichage()) > 3))
|
|
cout << "\n ** hysteresis bulk: warning dans le calcul de la contrainte a t+dt, on trouve "
|
|
<< " une valeur de pression -P= (" << MPr_t___tdt
|
|
<< ") > a la saturation = "<< Qzero
|
|
<< "\n ->arbitrairement on limite a la saturation "
|
|
<< endl;
|
|
// throw ErrNonConvergence_loiDeComportement(); // pour le débug
|
|
MPr_t___tdt = DSigne(MPr_t___tdt) * Qzero;
|
|
delta_MPr_Ratdt = MPr_t___tdt - MPr_R;
|
|
};
|
|
// la contrainte de retour
|
|
sigHH = gijHH * MPr_t___tdt;
|
|
// puis la sauvegarde dans save_resul
|
|
save_resul.MPr_tdt = MPr_t___tdt;
|
|
save_resul.fonction_aide_tdt = W_a;
|
|
save_resul.wprime_tdt = wprime;
|
|
//--------débug- traçage
|
|
#ifdef MISE_AU_POINT
|
|
if (Permet_affichage() == -77)
|
|
{ cout << " fin_traitement = " << fin_traitement
|
|
<< " save_resul.modif= " << save_resul.modif
|
|
<< " save_resul.nb_coincidence= " << save_resul.nb_coincidence
|
|
<< endl ;
|
|
};
|
|
#endif
|
|
|
|
|
|
};
|
|
|
|
/* // **********calcul d'une dérivée numérique-------------
|
|
double peti= 1.E-10;
|
|
double lambda_ver = lambda+peti;
|
|
double un_sur_1_plus_2_G_lambda_ver = 1. / (1. + deux_G*lambda_ver);
|
|
double un_sur_1_plus_2_G_lambda2_ver =
|
|
un_sur_1_plus_2_G_lambda_ver * un_sur_1_plus_2_G_lambda_ver;
|
|
double alphaa_ver = un_sur_1_plus_2_G_lambda_ver*deux_G;
|
|
double alphaa2_ver = un_sur_1_plus_2_G_lambda2_ver * deux_G_carre;
|
|
double omega_ver = alphaa_ver*K/(alphaa_ver+2.*K); double omega2_ver = omega_ver*omega_ver;
|
|
// a moins que lambda soit très grand on considère qu'omega est positif
|
|
// par contre lambda peut-être négatif
|
|
// if (lambda >= 0)
|
|
double delta_eps_equi_ver = 2.*lambda_ver*omega_ver * eps_elasBH(1,1);
|
|
// delta_eps_equi = 2.*lambda*omega * sqrt(c_c);
|
|
double epsilon_barre_ver = epsilon_barre_t + // def plastique cumulée
|
|
delta_eps_equi_ver;
|
|
// nouvelle valeur de la variation de sigma_barre
|
|
// et valeur de la tangente de la courbe d'écrouissage
|
|
Courbe1D::ValDer valder_ver = f_ecrouissage->Valeur_Et_derivee(epsilon_barre_ver);
|
|
double sig_equi_ver = valder_ver.valeur;
|
|
|
|
// calcul du résidu
|
|
double res_plas_ver = 3.*c_c*omega2_ver - sig_equi_ver * sig_equi_ver * un_tiers;
|
|
double der1 = 3.*c_c*(omega2_ver-omega2)/peti;
|
|
double dereps_barre = (epsilon_barre_ver -epsilon_barre)/peti;
|
|
double der2 = un_tiers*(- sig_equi_ver * sig_equi_ver - - sig_equi * sig_equi)/peti;
|
|
double der = (res_plas_ver - res_plas)/peti;
|
|
double delta_lambda_ver = - res_plas/der ;
|
|
// **********fin du calcul de la dérivée numérique------- */
|