// This file is part of the Herezh++ application.
//
// The finite element software Herezh++ is dedicated to the field
// of mechanics for large transformations of solid structures.
// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) .
//
// Herezh++ is distributed under GPL 3 license ou ultérieure.
//
// Copyright (C) 1997-2022 Université Bretagne Sud (France)
// AUTHOR : Gérard Rio
// E-MAIL : gerardrio56@free.fr
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// For more information, please consult: .
#include "F1_rond_F2.h"
#include "Sortie.h"
#include "ConstMath.h"
#include "MathUtil.h"
#include "CharUtil.h"
// CONSTRUCTEURS :
F1_rond_F2::F1_rond_F2(string nom) :
Courbe1D(nom,F1_ROND_F2),F1(NULL),F2(NULL)
{};
// constructeur fonction de deux courbes existantes et d'un nom
F1_rond_F2::F1_rond_F2(Courbe1D* FF1, Courbe1D* FF2, string nom):
Courbe1D(nom,F1_ROND_F2),F1(FF1),F2(FF2)
,nom_courbe1(""),nom_courbe2("")
{ // création de courbes locales que si elles étaient déjà locales
if (FF1->NomCourbe() == "_")
{F1=Courbe1D::New_Courbe1D(*(FF1));};
if (FF2->NomCourbe() == "_")
{F2=Courbe1D::New_Courbe1D(*(FF2));};
};
// de copie
F1_rond_F2::F1_rond_F2(const F1_rond_F2& Co) :
Courbe1D(Co)
,F1(Co.F1) // a priori on pointe sur les mêmes courbes internes
,F2(Co.F2) // a priori on pointe sur les mêmes courbes internes
,nom_courbe1(Co.nom_courbe1),nom_courbe2(Co.nom_courbe2)
{ // création de courbes locales que si elles étaient déjà locales
if (Co.F1->NomCourbe() == "_")
{F1=Courbe1D::New_Courbe1D(*(Co.F1));};
if (Co.F2->NomCourbe() == "_")
{F2=Courbe1D::New_Courbe1D(*(Co.F2));};
};
// de copie à partir d'une instance générale
F1_rond_F2::F1_rond_F2(const Courbe1D& Coo) :
Courbe1D(Coo)
{ if (Coo.Type_courbe() != F1_ROND_F2)
{ cout << "\n erreur dans le constructeur de copie pour une courbe F1_ROND_F2 "
<< " à partir d'une instance générale ";
cout << "\n F1_rond_F2::F1_rond_F2(const Courbe1D& Co) ";
Sortie(1);
};
// définition des données
F1_rond_F2 & Co = (F1_rond_F2&) Coo;
nom_courbe1 = Co.nom_courbe1;
nom_courbe2 = Co.nom_courbe2;
// création de courbes locales que si elles étaient déjà locales
if (Co.F1->NomCourbe() == "_")
{F1=Courbe1D::New_Courbe1D(*(Co.F1));}
else F1=Co.F1; // sinon cas d'une courbe globale
if (Co.F2->NomCourbe() == "_")
{F2=Courbe1D::New_Courbe1D(*(Co.F2));}
else F2=Co.F2; // sinon cas d'une courbe globale
};
// DESTRUCTEUR :
F1_rond_F2::~F1_rond_F2()
{ // on efface les courbes que si c'est des courbes locales
if ((F1 != NULL)&&(nom_courbe1=="i_interne_i")) delete F1;
if ((F2 != NULL)&&(nom_courbe2=="i_interne_i")) delete F2;};
// METHODES PUBLIQUES :
// --------- virtuelles ---------
// affichage de la courbe
void F1_rond_F2::Affiche() const
{ cout << "\n courbe composee : F1_rond_F2 : 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 premiere fonction: ";
if (F1->NomCourbe() == "_") {F1->Affiche();}
else {cout << F1->NomCourbe() << " ";};
cout << "\n seconde fonction: ";
if (F2->NomCourbe() == "_") {F2->Affiche();}
else {cout << F2->NomCourbe() << " ";};
cout << "\n ----- fin fonction F1_rond_F2 ----- ";
};
// vérification que tout est ok, pres à l'emploi
// ramène true si ok, false sinon
bool F1_rond_F2::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 (F2 == NULL) ret = false;
if (!ret && (ParaGlob::NiveauImpression() >0))
{ cout << "\n ***** la courbe n'est pas complete ";
this->Affiche();
};
return ret;
} ;
// dans le cas où les courbes membres sont des courbes externes
// fonction pour les définir
// les courbes sont défini en interne que si les courbes arguments sont elles même
// des courbes locales. c'est-à-dire si FF1->NomCourbe() ="_" alors on recrée une courbe
// interne avec new pour F1, sinon F1=FF1 et pas de création; idem pour f2
// dans le cas où FF1 ou FF1 est NULL on passe, pas de traitement pour ce pointeur
void F1_rond_F2::DefCourbesMembres(Courbe1D* FF1, Courbe1D* FF2)
{ // création de courbes locales que si elles étaient 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éfinie
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";
};
};
};
if (FF2 != NULL)
{if (FF2->NomCourbe() == "_") // cas où la courbe FF2 est non globale
{ if (F2==NULL)
{ // cas où la courbe locale n'est pas définie
F2=Courbe1D::New_Courbe1D(*(FF2));nom_courbe2="i_interne_i";
}
else if (F2->NomCourbe() == "_")
// cas où la courbe F2 est local et on veut la remplacer par une nouvelle locale
{ delete F2;
F2=Courbe1D::New_Courbe1D(*(FF2));nom_courbe2="i_interne_i";
}
else
// cas où la courbe F2 est global et on veut la remplacer par une locale
{ F2=Courbe1D::New_Courbe1D(*(FF2));nom_courbe2="i_interne_i";
};
}
else // cas où la courbe FF2 est globale
{ if (F2==NULL)
{ // cas où la courbe locale n'est pas définie
F2=FF2;nom_courbe2="e_externe_e";
}
else if (F2->NomCourbe() == "_")
// cas où la courbe F2 est local et on veut la remplacer par une globale
{ delete F2;
F2=FF2;nom_courbe2="e_externe_e";
}
else
// cas où la courbe F2 est global et on veut la remplacer par une globale
{ F2=FF2;nom_courbe2="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 F1_rond_F2::LectDonnParticulieres_courbes(const string& nom,UtilLecture * entreePrinc)
{ // entête de la courbe
if (nom == "") { *(entreePrinc->entree) >> nom_ref;}
else {nom_ref=nom;};
// lecture des courbes internes
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 F1_rond_F2::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;F1 = NULL;};
// puis la seconde courbe
entreePrinc->NouvelleDonnee(); // lecture d'une nouvelle ligne
// on lit l'entête
if(strstr(entreePrinc->tablcar,"courbe2=")==0)
{ cout << "\n erreur en lecture de l'entete "
<< " on attendait la chaine: courbe2= ";
entreePrinc->MessageBuffer("**erreur1 F1_rond_F2::LectureDonneesParticulieres**");
throw (UtilLecture::ErrNouvelleDonnee(-1));
Sortie(1);
};
*(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_courbe2 = "_"; // on signale que c'est une courbe interne
F2 = Courbe1D::New_Courbe1D(nom_courbe2,Id_Nom_Courbe1D (nom_lu.c_str()));
// lecture de la courbe
F2->LectDonnParticulieres_courbes (nom_courbe2,entreePrinc);
nom_courbe2="i_interne_i";
}
else
// sinon on retiend le nom pour une complétion future
{nom_courbe2 = nom_lu;F2 = NULL;};
};
// 1) renseigne si la courbe dépend d'autre courbe ou non
bool F1_rond_F2::DependAutreCourbes() const
{ bool ret=false;
if(F1 == NULL) {ret=true;}
// else if (nom_courbe1!="i_interne_i") {ret=true;};
if(F2 == NULL) {ret=true;}
// if (nom_courbe2!="i_interne_i") {ret=true;};
return ret;
};
// 2) retourne une liste de nom correspondant aux noms de courbes dont dépend *this
list & F1_rond_F2::ListDependanceCourbes(list & 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)
{ if (nom_courbe1 != "i_interne_i")
{lico.push_back(nom_courbe1);} // cas normal
else
{cout << "\n *** erreur, la courbe 1 est declaree interne, mais n'est pas definie "
<< " ce n'est pas normale, la suite est impossible *** "
<< flush;
Sortie(1);
};
}
if(F2 == NULL)
{ if (nom_courbe2 != "i_interne_i")
{lico.push_back(nom_courbe2);} // cas normal
else
{cout << "\n *** erreur, la courbe 2 est declaree interne, mais n'est pas definie "
<< " ce n'est pas normale, la suite est impossible *** "
<< flush;
Sortie(1);
};
};
return lico;
};
// 3) établit la connection entre la demande de *this et les courbes passées en paramètres
void F1_rond_F2::Lien_entre_courbe (list & liptco)
{ Courbe1D* FF1=NULL; Courbe1D* FF2 = NULL;
list ::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;};
};
if (F2==NULL)
{ // on cherche la courbe correspondante
for (ili=liptco.begin();ili!=ilifin;ili++)
if ((*ili)->NomCourbe() == nom_courbe2) {FF2=(*ili);break;};
};
// et on définit les courbes
this->DefCourbesMembres(FF1,FF2);
};
// def info fichier de commande
void F1_rond_F2::Info_commande_Courbes1D(UtilLecture & entreePrinc)
{
ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
sort << "\n#............................................"
<< "\n# *** exemple 1 de definition d'une courbe composee F1_ROND_F2 ****"
<< "\n# ici on indique les noms des courbes internes qui doivent donc etre"
<< "\n# definis par ailleurs "
<< "\n courbe_exemple1 F1_ROND_F2 # nom de la courbe "
<< "\n courbe1= fonction_temperature # def de la premiere courbe"
<< "\n courbe2= transfo1 # def de la seconde courbe"
<< "\n "
<< "\n# *** exemple 2 de definition d'une courbe composee F1_ROND_F2 ****"
<< "\n# ici on indique explicitement les courbes "
<< "\n# definis par ailleurs "
<< "\n courbe_exemple2 F1_ROND_F2 # nom de la courbe "
<< "\n courbe1= COURBE_UN_MOINS_COS # def de la premiere courbe"
<< "\n # def des coeff de la courbe demi sinus f(t)= c/2*(1-cos((x-a)*Pi/(b-a)))"
<< "\n # pour x < a => f=0, pour x>b => f=c"
<< "\n a= 0. b= 1. c= 1."
<< "\n courbe2= COURBEPOLYNOMIALE # def de la seconde courbe"
<< "\n # def des coefficients d'un polynome du troisieme degre 1+3x+6x^2+8x^3"
<< "\n debut_coef= 1. 3. 6. 8. fin_coef "
<< "\n "
<< endl;
};
// ramène la valeur
double F1_rond_F2::Valeur(double x)
{ return F1->Valeur(F2->Valeur(x));};
// ramène la valeur et la dérivée en paramètre
Courbe1D::ValDer F1_rond_F2::Valeur_Et_derivee(double x)
{ ValDer ret1 = F2->Valeur_Et_derivee(x);
ValDer ret2 = F1->Valeur_Et_derivee(ret1.valeur);
ValDer ret; ret.valeur=ret2.valeur; ret.derivee=ret1.derivee*ret2.derivee;
return ret;
};
// ramène la dérivée
double F1_rond_F2::Derivee(double x)
{ ValDer ret1 = F2->Valeur_Et_derivee(x);
ValDer ret2 = F1->Valeur_Et_derivee(ret1.valeur);
return ret1.derivee*ret2.derivee;
};
// ramène la valeur et les dérivées première et seconde en paramètre
Courbe1D::ValDer2 F1_rond_F2::Valeur_Et_der12(double x)
{ ValDer2 ret1 = F2->Valeur_Et_der12(x);
ValDer2 ret2 = F1->Valeur_Et_der12(ret1.valeur);
ValDer2 ret; ret.valeur=ret2.valeur; ret.derivee=ret1.derivee*ret2.derivee;
ret.der_sec = ret1.der_sec * ret2.derivee + Sqr(ret1.derivee) * ret2.der_sec;
return ret;
};
// ramène la dérivée seconde
double F1_rond_F2::Der_sec(double x)
{ ValDer2 ret1 = F2->Valeur_Et_der12(x);
ValDer2 ret2 = F1->Valeur_Et_der12(ret1.valeur);
return ret1.der_sec * ret2.derivee + Sqr(ret1.derivee) * ret2.der_sec;
};
// 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 F1_rond_F2::Valeur_stricte(double x)
{ Valbool ret1 = F2->Valeur_stricte(x);
Valbool ret = F1->Valeur_stricte(ret1.valeur);
// si un des deux n'est pas dedans le tout n'est pas dedans
if ((!ret1.dedans) || (!ret.dedans)) ret.dedans = false;
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 F1_rond_F2::Valeur_Et_derivee_stricte(double x)
{ ValDerbool ret1 = F2->Valeur_Et_derivee_stricte(x);
ValDerbool ret2 = F1->Valeur_Et_derivee_stricte(ret1.valeur);
ValDerbool ret; ret.valeur=ret2.valeur; ret.derivee=ret1.derivee*ret2.derivee;
if ((!ret1.dedans) || (!ret2.dedans))
{ret.dedans = false;}
else
{ ret.dedans = true;};
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 F1_rond_F2::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 != "F1_ROND_F2")
{ cout << "\n erreur dans la verification du type de courbe lue ";
cout << "\n F1_rond_F2::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 F1_rond_F2::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;
};
};
// pour la courbe2
ent >> nom1 >> nom2 >> nom3;
if (nom1 != "courbe2=")
{ cout << "\n erreur dans la verification du type, on attendait le mot cle courbe2= "
<< " et on a lu " << nom1 << " ";
cout << "\n F1_rond_F2::Lecture_base_info(... ";
Sortie(1);
}
else
{ if (nom2 == "COURBE_INTERNE2")
{// cas d'une courbe en interne
// 1) on commence par effacer la courbe existante si nécessaire
if (F2 != NULL) {if (F2->NomCourbe() == "_") delete F2;};
// 2) on crée la courbe adoc
nom2="_";
F2 = Courbe1D::New_Courbe1D(nom2,Id_Nom_Courbe1D (nom3.c_str()));
// 3) on lit les données particulières
F2->Lecture_base_info(ent,cas);
nom_courbe2="i_interne_i";
}
else
{// cas d'une courbe externe on lit le nom
nom_courbe1 = nom2;
};
};
}
};
// cas donne le niveau de sauvegarde
// = 1 : on sauvegarde tout
// = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
void F1_rond_F2::Ecriture_base_info(ofstream& sort,const int cas)
{ // on n'a que des grandeurs constantes
if (cas == 1)
{ sort << " F1_ROND_F2 ";
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();;};
if (F2->NomCourbe() == "_")
{// cas d'une courbe interne
sort << "\n courbe2= COURBE_INTERNE2 " << F2->Type_courbe();
F2->Ecriture_base_info(sort,cas);
}
else
// cas d'une courbe externe
{sort << "\n courbe2= " << F2->NomCourbe() << " " << F2->Type_courbe();};
};
};
// sortie du schemaXML: en fonction de enu
void F1_rond_F2::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;
}
};
};