Herezh_dev/herezh_pp/Util/Courbes/F_cyclique.cc

551 lines
22 KiB
C++
Executable file

// 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 "F_cyclique.h"
#include "Sortie.h"
#include "ConstMath.h"
#include "MathUtil.h"
#include "CharUtil.h"
// CONSTRUCTEURS :
F_cyclique::F_cyclique(string nom) :
Courbe1D(nom,F_CYCLIQUE),F1(NULL)
,ampli(1.),longcycl(ConstMath::tresgrand),decalx(0.),decaly(0.)
{};
// constructeur fonction d'une courbe existante et d'un nom
F_cyclique::F_cyclique(Courbe1D* FF1, string nom):
Courbe1D(nom,F_CYCLIQUE),F1(FF1)
,nom_courbe1("")
,ampli(1.),longcycl(ConstMath::tresgrand),decalx(0.),decaly(0.)
{ // création d'une courbe locale que si elle était déjà locale
if (FF1->NomCourbe() == "_")
{F1=Courbe1D::New_Courbe1D(*(FF1));};
};
// de copie
F_cyclique::F_cyclique(const F_cyclique& Co) :
Courbe1D(Co)
,F1(Co.F1) // a priori on pointe sur la même courbe interne
,nom_courbe1(Co.nom_courbe1)
,ampli(Co.ampli),longcycl(Co.longcycl),decalx(Co.decalx),decaly(Co.decaly)
{ // création d'une courbe locale que si elle était déjà locale
if (Co.F1->NomCourbe() == "_")
{F1=Courbe1D::New_Courbe1D(*(Co.F1));};
};
// de copie à partir d'une instance générale
F_cyclique::F_cyclique(const Courbe1D& Coo) :
Courbe1D(Coo)
{ if (Coo.Type_courbe() != F_CYCLIQUE)
{ cout << "\n erreur dans le constructeur de copie pour une courbe F_CYCLIQUE "
<< " à partir d'une instance générale ";
cout << "\n F_cyclique::F_cyclique(const Courbe1D& Co) ";
Sortie(1);
};
// définition des données
F_cyclique & Co = (F_cyclique&) Coo;
nom_courbe1 = Co.nom_courbe1;
ampli=Co.ampli;
longcycl=Co.longcycl;
decalx=Co.decalx; decaly=Co.decaly;
// création d'une courbe locale que si elle était déjà locale
if (Co.F1->NomCourbe() == "_")
{F1=Courbe1D::New_Courbe1D(*(Co.F1));}
else F1=Co.F1; // sinon cas d'une courbe globale
};
// DESTRUCTEUR :
F_cyclique::~F_cyclique()
{ // on efface la courbe que si c'est une courbe locale
if ((F1 != NULL)&&(nom_courbe1=="i_interne_i")) delete F1;
};
// METHODES PUBLIQUES :
// --------- virtuelles ---------
// affichage de la courbe
void F_cyclique::Affiche() const
{ cout << "\n courbe composee : F_cyclique : nom_ref= " << nom_ref;
// si c'est une courbe interne on l'affiche globalement
// si c'est une courbe globale, on n'affiche que son nom
cout << "\n fonction de base: ";
if (F1->NomCourbe() == "_") {F1->Affiche();}
else {cout << F1->NomCourbe() << " ";};
cout << "\n facteur d'amplification= " << ampli
<< " longueur_cycle= " << longcycl
<< " decalagex= " << decalx << " decalagey= " << decaly << " " ;
cout << "\n ----- fin fonction F_cyclique ----- ";
};
// vérification que tout est ok, pres à l'emploi
// ramène true si ok, false sinon
bool F_cyclique::Complet_courbe()const
{ bool ret = Complet_var(); // on regarde du coté de la classe mère tout d'abord
// puis les variables propres
if (F1 == NULL) ret = false;
if (!ret && (ParaGlob::NiveauImpression() >0))
{ cout << "\n ***** la courbe n'est pas complete ";
this->Affiche();
};
return ret;
} ;
// dans le cas où la courbe membre est une courbe externe
// fonction pour la définir
// la courbe est défini en interne que si la courbe argument est elle même
// une courbe locale. c'est-à-dire si FF1->NomCourbe() ="_" alors on recrée une courbe
// interne avec new pour F1, sinon F=FF1 et pas de création;
// dans le cas où FF1 ou FF1 est NULL on passe, pas de traitement pour ce pointeur
void F_cyclique::DefCourbesMembres(Courbe1D* FF1)
{ // création d'une courbe locale que si elle était déjà locales
if (FF1 != NULL)
{if (FF1->NomCourbe() == "_") // cas où FF1 est une courbe non globale
{ if (F1==NULL)
{ // cas où la courbe locale n'est pas défini mais on veut une courbe interne
F1=Courbe1D::New_Courbe1D(*(FF1));nom_courbe1="i_interne_i";
}
else if (F1->NomCourbe() == "_")
// cas où la courbe F1 est local et on veut la remplacer par une nouvelle locale
{ delete F1;
F1=Courbe1D::New_Courbe1D(*(FF1));nom_courbe1="i_interne_i";
}
else
// cas où la courbe F1 est global et on veut la remplacer par une locale
{ F1=Courbe1D::New_Courbe1D(*(FF1));nom_courbe1="i_interne_i";
};
}
else // cas ou FF1 est une courbe globale
{ if (F1==NULL)
{ // cas où la courbe locale n'est pas définir
F1=FF1;nom_courbe1="e_externe_e";
}
else if (F1->NomCourbe() == "_")
// cas où la courbe F1 est local et on veut la remplacer par une globale
{ delete F1;
F1=FF1;nom_courbe1="e_externe_e";
}
else
// cas où la courbe F1 est global et on veut la remplacer par une globale
{ F1=FF1;nom_courbe1="e_externe_e";
};
};
};
};
// Lecture des donnees de la classe sur fichier
// le nom passé en paramètre est le nom de la courbe
// s'il est vide c-a-d = "", la methode commence par lire le nom sinon
// ce nom remplace le nom actuel
void F_cyclique::LectDonnParticulieres_courbes(const string& nom,UtilLecture * entreePrinc)
{ // entête de la courbe
if (nom == "") { *(entreePrinc->entree) >> nom_ref;}
else {nom_ref=nom;};
// lecture de la courbe interne
entreePrinc->NouvelleDonnee(); // lecture d'une nouvelle ligne
// on lit l'entête
if(strstr(entreePrinc->tablcar,"courbe1=")==0)
{ cout << "\n erreur en lecture de l'entete "
<< " on attendait la chaine: courbe1= ";
entreePrinc->MessageBuffer("**erreur1 F_cyclique::LectureDonneesParticulieres**");
throw (UtilLecture::ErrNouvelleDonnee(-1));
Sortie(1);
};
string toto,nom_lu;
*(entreePrinc->entree) >> toto >> nom_lu;
// on regarde si la courbe1 existe, si oui on récupère la référence
if (Type_EnumCourbe1D_existe(nom_lu))
// cas ou c'est un nom de type de courbe -> lecture directe
{ nom_courbe1 = "_"; // on signale que c'est une courbe interne
F1 = Courbe1D::New_Courbe1D(nom_courbe1,Id_Nom_Courbe1D (nom_lu.c_str()));
// lecture de la courbe
F1->LectDonnParticulieres_courbes (nom_courbe1,entreePrinc);
nom_courbe1="i_interne_i";
}
else
// sinon on retiend le nom pour une complétion future
{nom_courbe1 = nom_lu;};
// lecture de l'amplification et de la longueur du cycle
entreePrinc->NouvelleDonnee(); // lecture d'une nouvelle ligne
*(entreePrinc->entree) >> nom_lu >> longcycl;
if (nom_lu != "longueur_cycle_=")
{ cout << "\n erreur en lecture de la longueur du cycle "
<< " on attendait la chaine: longueur_cycle_= et on a lue " << nom_lu;
entreePrinc->MessageBuffer("**erreur1 F_cyclique::LectureDonneesParticulieres**");
throw (UtilLecture::ErrNouvelleDonnee(-1));
Sortie(1);
};
if (longcycl <= ConstMath::petit)
{ cout << "\n ****** attention ****** la longueur de cycle lue vaut: " << longcycl
<< " c'est une grandeur tres petite, ce qui peut entrainer des erreurs de calcul !! ";
};
if(strstr(entreePrinc->tablcar,"amplification_=")!=0)
// cas ou on veut définir un facteur d'amplification
{ *(entreePrinc->entree) >> nom_lu >> ampli;
if (nom_lu != "amplification_=")
{ cout << "\n erreur en lecture du facteur d'amplification "
<< " on attendait la chaine: amplification_= et on a lue " << nom_lu;
entreePrinc->MessageBuffer("**erreur1 F_cyclique::LectureDonneesParticulieres**");
throw (UtilLecture::ErrNouvelleDonnee(-1));
Sortie(1);
};
};
if(strstr(entreePrinc->tablcar,"decalageX_=")!=0)
// cas ou on veut définir un décalage initiale
{ *(entreePrinc->entree) >> nom_lu >> decalx;
if (nom_lu != "decalageX_=")
{ cout << "\n erreur en lecture du decalage initiale en x "
<< " on attendait la chaine: decalageX_= et on a lue " << nom_lu;
entreePrinc->MessageBuffer("**erreur1 F_cycle_add::LectureDonneesParticulieres**");
throw (UtilLecture::ErrNouvelleDonnee(-1));
Sortie(1);
};
};
if(strstr(entreePrinc->tablcar,"decalageY_=")!=0)
// cas ou on veut définir un décalage initiale
{ *(entreePrinc->entree) >> nom_lu >> decaly;
if (nom_lu != "decalageY_=")
{ cout << "\n erreur en lecture du decalage en y initiale "
<< " on attendait la chaine: decalageY_= et on a lue " << nom_lu;
entreePrinc->MessageBuffer("**erreur1 F_cycle_add::LectureDonneesParticulieres**");
throw (UtilLecture::ErrNouvelleDonnee(-1));
Sortie(1);
};
};
};
// 1) renseigne si la courbe dépend d'autre courbe ou non
bool F_cyclique::DependAutreCourbes() const
{ bool ret=false;
if(F1 == NULL) {ret=true;}
else if (nom_courbe1!="i_interne_i") {ret=true;};
return ret;
};
// 2) retourne une liste de nom correspondant aux noms de courbes dont dépend *this
list <string>& F_cyclique::ListDependanceCourbes(list <string>& lico) const
{ // tout d'abord on vide la liste passée en paramètres
if (lico.size() != 0) lico.erase(lico.begin(),lico.end());
// on remplit en fonction de l'état
if(F1 == NULL) lico.push_back(nom_courbe1);
return lico;
};
// 3) établit la connection entre la demande de *this et les courbes passées en paramètres
void F_cyclique::Lien_entre_courbe (list <Courbe1D *>& liptco)
{ Courbe1D* FF1=NULL; Courbe1D* FF2 = NULL;
list <Courbe1D *>::iterator ili,ilifin=liptco.end();
if (F1==NULL)
{ // on cherche la courbe correspondante
for (ili=liptco.begin();ili!=ilifin;ili++)
if ((*ili)->NomCourbe() == nom_courbe1) {FF1=(*ili);break;};
};
// et on définit les courbes
this->DefCourbesMembres(FF1);
};
// def info fichier de commande
void F_cyclique::Info_commande_Courbes1D(UtilLecture & entreePrinc)
{
ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
sort << "\n#............................................"
<< "\n# il s'agit d'une fonction qui est cyclique, a chaque debut de cycle"
<< "\n# elle prend la valeur de la fin du cycle precedent + , la valeur d'une "
<< "\n# fonction de base multipliee par un facteur d'amplitude puissance n, "
<< "\n# n etant le nombre de cycle qui vaut 1 par defaut"
<< "\n# ainsi on doit indiquer la longueur du cycle, mais le facteur d'amplitude est "
<< "\n# facultatif. On indique au debut de la declaration, la fonction de base "
<< "\n# Remarque: le premier cycle commence a x=0. "
<< "\n# *** exemple 1 de definition d'une courbe composee F_CYCLIQUE ****"
<< "\n# 1) ici on indique le nom de la courbe interne qui doit donc etre"
<< "\n# definis par ailleurs "
<< "\n courbe_exemple1 F_CYCLIQUE # nom de la courbe "
<< "\n courbe1= fonction_temperature # def de la courbe interne"
<< "\n longueur_cycle_= 10 amplification_= 2 "
<< "\n "
<< "\n# Il est egalement possible d'introduire un decalage en x et y. Le decalage en x "
<< "\n# est soustrait a la valeur courante de x, tandis que le decalage en y est ajoute "
<< "\n# a la valeur finale de la fonction. Exemple de syntaxe "
<< "\n longueur_cycle_= 10 amplification_= 2 decalageX_= 10. decalageY_= 3. "
<< "\n "
<< "\n# *** exemple 2 de definition d'une courbe composee F_CYCLIQUE ****"
<< "\n# ici on indique explicitement la courbe interne "
<< "\n# definis par ailleurs "
<< "\n courbe_exemple2 F_CYCLIQUE # nom de la courbe "
<< "\n# def d'une fonction echelon (interne) avec une attenuation des angles "
<< "\n courbe1= COURBEPOLYLINEAIRE_1_D "
<< "\n Debut_des_coordonnees_des_points "
<< "\n Coordonnee dim= 2 0. 0. "
<< "\n Coordonnee dim= 2 0.2 0.05 "
<< "\n Coordonnee dim= 2 0.4 0.2 "
<< "\n Coordonnee dim= 2 0.6 0.8 "
<< "\n Coordonnee dim= 2 0.8 0.95 "
<< "\n Coordonnee dim= 2 1. 1. "
<< "\n Coordonnee dim= 2 10. 1. "
<< "\n Fin_des_coordonnees_des_points "
<< "\n# def des parametres internes du cycle "
<< "\n longueur_cycle_= 5. "
<< "\n "
<< endl;
};
// ramène la valeur
double F_cyclique::Valeur(double x)
{ int n=(x-decalx)/longcycl;
double A_puiss_n = 1.;
if (n>0) A_puiss_n=PUISSN(ampli,n);
double resul = decaly;
if (Dabs(ampli-1) > ConstMath::unpeupetit)
{resul += (A_puiss_n-1.)/(ampli-1.) * F1->Valeur(longcycl)
+ A_puiss_n * F1->Valeur(x-n*longcycl-decalx);
}
else
{resul += n * F1->Valeur(longcycl)
+ A_puiss_n * F1->Valeur(x-n*longcycl-decalx);
}
// cout << "\n cyclique : valeur = " << resul;
return resul;
};
// ramène la valeur et la dérivée en paramètre
Courbe1D::ValDer F_cyclique::Valeur_Et_derivee(double x)
{ int n=(x-decalx)/longcycl;
double A_puiss_n = 1.;
if (n>0) A_puiss_n=PUISSN(ampli,n);
ValDer ret1 = F1->Valeur_Et_derivee(x-n*longcycl-decalx);
ValDer ret; // le retour
if (Dabs(ampli-1) > ConstMath::unpeupetit)
{ ret.valeur = decaly +(A_puiss_n-1.)/(ampli-1.) * F1->Valeur(longcycl)
+ A_puiss_n * ret1.valeur;
}
else
{ ret.valeur = decaly + n * F1->Valeur(longcycl)
+ A_puiss_n * ret1.valeur;
};
ret.derivee = A_puiss_n * ret1.derivee;
return ret;
};
// ramène la dérivée
double F_cyclique::Derivee(double x)
{ int n=(x-decalx)/longcycl;
double derivee = F1->Derivee(x-n*longcycl-decalx);
double A_puiss_n = 1.;
if (n>0) A_puiss_n=PUISSN(ampli,n);
return (A_puiss_n * derivee);
};
// ramène la valeur et les dérivées première et seconde en paramètre
Courbe1D::ValDer2 F_cyclique::Valeur_Et_der12(double x)
{ int n=(x-decalx)/longcycl;
double A_puiss_n = 1.;
if (n>0) A_puiss_n=PUISSN(ampli,n);
ValDer2 ret1 = F1->Valeur_Et_der12(x-n*longcycl-decalx);
ValDer2 ret; // le retour
if (Dabs(ampli-1) > ConstMath::unpeupetit)
{ ret.valeur = decaly +(A_puiss_n-1.)/(ampli-1.) * F1->Valeur(longcycl)
+ A_puiss_n * ret1.valeur;
}
else
{ ret.valeur = decaly + n * F1->Valeur(longcycl)
+ A_puiss_n * ret1.valeur;
};
ret.derivee = A_puiss_n * ret1.derivee;
ret.der_sec = A_puiss_n * ret1.der_sec;
return ret;
};
// ramène la dérivée seconde
double F_cyclique::Der_sec(double x)
{ int n=(x-decalx)/longcycl;
double derivee_seconde = F1->Der_sec(x-n*longcycl-decalx);
double A_puiss_n = 1.;
if (n>0) A_puiss_n=PUISSN(ampli,n);
return (A_puiss_n * derivee_seconde);
};
// ramène la valeur si dans le domaine strictement de définition
// si c'est inférieur au x mini, ramène la valeur minimale possible de y
// si supérieur au x maxi , ramène le valeur maximale possible de y
Courbe1D::Valbool F_cyclique::Valeur_stricte(double x)
{ int n=(x-decalx)/longcycl;
double A_puiss_n = 1.;
if (n>0) A_puiss_n=PUISSN(ampli,n);
Valbool ret1 = F1->Valeur_stricte(x-n*longcycl-decalx);
Valbool ret2 = F1->Valeur_stricte(longcycl);
Valbool ret; // le retour
if (Dabs(ampli-1) > ConstMath::unpeupetit)
{ ret.valeur= decaly+(A_puiss_n-1.)/(ampli-1.) * ret2.valeur + A_puiss_n * ret1.valeur;}
else { ret.valeur= decaly+ n * ret2.valeur + A_puiss_n * ret1.valeur;}
ret.dedans = ret1.dedans && ret2.dedans ;
return ret;
};
// ramène la valeur et la dérivée si dans le domaine strictement de définition
// si c'est inférieur au x mini, ramène la valeur minimale possible de y et Y' correspondant
// si supérieur au x maxi , ramène le valeur maximale possible de y et Y' correspondant
Courbe1D::ValDerbool F_cyclique::Valeur_Et_derivee_stricte(double x)
{ int n=(x-decalx)/longcycl;
double A_puiss_n = 1.;
if (n>0) A_puiss_n=PUISSN(ampli,n);
ValDerbool ret1 = F1->Valeur_Et_derivee_stricte(x-n*longcycl-decalx);
Valbool ret2 = F1->Valeur_stricte(longcycl);
ValDerbool ret; // le retour
if (Dabs(ampli-1) > ConstMath::unpeupetit)
{ ret.valeur= decaly+(A_puiss_n-1.)/(ampli-1.) * ret2.valeur + A_puiss_n * ret1.valeur;}
else { ret.valeur= decaly+n * ret2.valeur + A_puiss_n * ret1.valeur;}
ret.derivee = A_puiss_n * ret1.derivee;
ret.dedans = ret1.dedans && ret2.dedans ;
return ret;
};
//----- lecture écriture de restart -----
// cas donne le niveau de la récupération
// = 1 : on récupère tout
// = 2 : on récupère uniquement les données variables (supposées comme telles)
void F_cyclique::Lecture_base_info(ifstream& ent,const int cas)
{ // on n'a que des grandeurs constantes
if (cas == 1)
{ string nom;
// lecture et vérification de l'entête
ent >> nom;
if (nom != "F_CYCLIQUE")
{ cout << "\n erreur dans la verification du type de courbe lue ";
cout << "\n F_cyclique::Lecture_base_info(... ";
Sortie(1);
}
// lecture des infos
string nom1,nom2,nom3;
// pour la courbe1
ent >> nom1 >> nom2 >> nom3;
if (nom1 != "courbe1=")
{ cout << "\n erreur dans la verification du type, on attendait le mot cle courbe1= "
<< " et on a lu " << nom1 << " ";
cout << "\n F_cyclique::Lecture_base_info(... ";
Sortie(1);
}
else
{ if (nom2 == "COURBE_INTERNE1")
{// cas d'une courbe en interne
// 1) on commence par effacer la courbe existante si nécessaire
if (F1 != NULL) {if (F1->NomCourbe() == "_") delete F1;};
// 2) on crée la courbe adoc
nom2="_";
F1 = Courbe1D::New_Courbe1D(nom2,Id_Nom_Courbe1D (nom3.c_str()));
// 3) on lit les données particulières
F1->Lecture_base_info(ent,cas);
nom_courbe1="i_interne_i";
}
else
{// cas d'une courbe externe on lit le nom
nom_courbe1 = nom2;
};
};
// amplification et longueur du cycle
ent >> nom1 >> ampli >> nom2 ;
if (nom1 != "amplification_=")
{ cout << "\n erreur dans la lecture du facteur d'amplification on attendait amplification_= "
<< " et on a lu " << nom1 << " ";
cout << "\n F_cyclique::Lecture_base_info(... ";
Sortie(1);
};
if (nom2 != "longueur_cycle_=")
{ cout << "\n erreur dans la lecture de la longueur du cycle on attendait longueur_cycle_= "
<< " et on a lu " << nom2 << " ";
cout << "\n F_cyclique::Lecture_base_info(... ";
Sortie(1);
};
ent >> nom1 >> decalx >> nom2 >> decaly ;
if (nom1 != "decalageX_=")
{ cout << "\n erreur dans la lecture de la longueur du cycle on attendait decalageX_= "
<< " et on a lu " << nom1 << " ";
cout << "\n F_cyclique::Lecture_base_info(... ";
Sortie(1);
};
if (nom2 != "decalageY_=")
{ cout << "\n erreur dans la lecture de la longueur du cycle on attendait decalageY_= "
<< " et on a lu " << nom2 << " ";
cout << "\n F_cyclique::Lecture_base_info(... ";
Sortie(1);
};
};
};
// cas donne le niveau de sauvegarde
// = 1 : on sauvegarde tout
// = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
void F_cyclique::Ecriture_base_info(ofstream& sort,const int cas)
{ // on n'a que des grandeurs constantes
if (cas == 1)
{ sort << " F_CYCLIQUE ";
if (F1->NomCourbe() == "_")
{// cas d'une courbe interne
sort << "\n courbe1= COURBE_INTERNE1 " << F1->Type_courbe();
F1->Ecriture_base_info(sort,cas);
}
else
// cas d'une courbe externe
{sort << "\n courbe1= " << F1->NomCourbe() << " " << F1->Type_courbe();;};
// amplification et longueur du cycle
sort << "\n amplification_= " << ampli
<< " longueur_cycle_= " << longcycl
<< " decalageX_= " << decalx << " decalageY_= " << decaly << " " ;
};
};
// sortie du schemaXML: en fonction de enu
//void F_cyclique::SchemaXML_Courbes1D(ofstream& sort,const Enum_IO_XML enu)
void F_cyclique::SchemaXML_Courbes1D(ofstream& ,const Enum_IO_XML enu)
{
switch (enu)
{ case XML_TYPE_GLOBAUX :
{
break;
}
case XML_IO_POINT_INFO :
{
break;
}
case XML_IO_POINT_BI :
{
break;
}
case XML_IO_ELEMENT_FINI :
{
break;
}
};
};