// 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-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 . // // For more information, please consult: . #include "F1_plus_F2.h" #include "Sortie.h" #include "ConstMath.h" #include "MathUtil.h" #include "CharUtil.h" // CONSTRUCTEURS : F1_plus_F2::F1_plus_F2(string nom) : Courbe1D(nom,F1_PLUS_F2),F1(NULL),F2(NULL) ,ponder1(1.),ponder2(1.) {}; // constructeur fonction de deux courbes existantes et d'un nom F1_plus_F2::F1_plus_F2(Courbe1D* FF1, Courbe1D* FF2, string nom): Courbe1D(nom,F1_PLUS_F2),F1(FF1),F2(FF2) ,nom_courbe1(""),nom_courbe2("") ,ponder1(1.),ponder2(1.) { // 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_plus_F2::F1_plus_F2(const F1_plus_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) ,ponder1(Co.ponder1),ponder2(Co.ponder2) { // 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_plus_F2::F1_plus_F2(const Courbe1D& Coo) : Courbe1D(Coo) { if (Coo.Type_courbe() != F1_PLUS_F2) { cout << "\n erreur dans le constructeur de copie pour une courbe F1_PLUS_F2 " << " à partir d'une instance générale "; cout << "\n F1_plus_F2::F1_plus_F2(const Courbe1D& Co) "; Sortie(1); }; // définition des données F1_plus_F2 & Co = (F1_plus_F2&) Coo; nom_courbe1 = Co.nom_courbe1; nom_courbe2 = Co.nom_courbe2; ponder1 = Co.ponder1; ponder2 = Co.ponder2; // 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_plus_F2::~F1_plus_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_plus_F2::Affiche() const { cout << "\n courbe composee : F1_plus_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 ponderations: ponder_ "<< ponder1 << " ponder_ "<< ponder2; cout << "\n ----- fin fonction F1_plus_F2 ----- "; }; // vérification que tout est ok, pres à l'emploi // ramène true si ok, false sinon bool F1_plus_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_plus_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é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"; }; }; }; 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éfini 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éfinir 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_plus_F2::LectDonnParticulieres_courbes(const string& nom,UtilLecture * entreePrinc) { string nom_class_methode("F1_plus_F2::LectDonnParticulieres_courbes"); // 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_plus_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;}; // on lit une pondération éventuelle if(strstr(entreePrinc->tablcar,"ponder_")!=0) { // idem pour un double string mot_cle("ponder_"); entreePrinc->Lecture_un_parametre_double (1.,nom_class_methode,0.,-1.,mot_cle,ponder1); }; // 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_plus_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_courbe1="i_interne_i"; } else // sinon on retiend le nom pour une complétion future {nom_courbe2 = nom_lu;}; // on lit une pondération éventuelle if(strstr(entreePrinc->tablcar,"ponder_")!=0) { // idem pour un double string mot_cle("ponder_"); entreePrinc->Lecture_un_parametre_double (1.,nom_class_methode,0.,-1.,mot_cle,ponder2); }; }; // 1) renseigne si la courbe dépend d'autre courbe ou non bool F1_plus_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_plus_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) lico.push_back(nom_courbe1); if(F2 == NULL) lico.push_back(nom_courbe2); return lico; }; // 3) établit la connection entre la demande de *this et les courbes passées en paramètres void F1_plus_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_plus_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_PLUS_F2 ****" << "\n# ici on indique les noms des courbes internes qui doivent donc etre" << "\n# definis par ailleurs " << "\n courbe_exemple1 F1_PLUS_F2 # nom de la courbe " << "\n courbe1= fonction_temperature1 # def de la premiere courbe" << "\n courbe2= fonction_temperature2 # def de la seconde courbe" << "\n " << "\n on peut egalement definir une ponderation multiplicative pour chaque courbe " << "\n a la suite de la courbe1 on indique le mot cle ponder_ suivi d'un reel " << "\n idem pour la seconde courbe avec le mot cle ponder_ " << "\n courbe_exemple2 F1_PLUS_F2 # nom de la courbe " << "\n courbe1= fonction_temperature1 ponder_ 2. # def de la premiere courbe ponderee " << "\n courbe2= fonction_temperature2 ponder_ 0.5 # def de la seconde courbe ponderee " << "\n " << "\n# -- exemple 3 de definition d'une courbe composee F1_PLUS_F2 ****" << "\n# ici on indique explicitement les courbes " << "\n courbe_exemple3 F1_PLUS_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# -- exemple 4 : idem exemple 3 mais avec ponderations " << "\n# ici on indique explicitement les courbes " << "\n courbe_exemple4 F1_PLUS_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. ponder_ 2. " << "\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 ponder_ 3. " << "\n " << endl; }; // ramène la valeur double F1_plus_F2::Valeur(double x) { return ponder1*F1->Valeur(x)+ponder2*F2->Valeur(x);}; // ramène la valeur et la dérivée en paramètre Courbe1D::ValDer F1_plus_F2::Valeur_Et_derivee(double x) { ValDer ret1 = F2->Valeur_Et_derivee(x); ValDer ret2 = F1->Valeur_Et_derivee(x); ValDer ret; ret.valeur=ponder1*ret1.valeur+ponder2*ret2.valeur; ret.derivee=ponder1*ret1.derivee+ponder2*ret2.derivee; return ret; }; // ramène la dérivée double F1_plus_F2::Derivee(double x) { ValDer ret1 = F2->Valeur_Et_derivee(x); ValDer ret2 = F1->Valeur_Et_derivee(x); return ponder1*ret1.derivee+ponder2*ret2.derivee; }; // ramène la valeur et les dérivées première et seconde en paramètre Courbe1D::ValDer2 F1_plus_F2::Valeur_Et_der12(double x) { ValDer2 ret1 = F2->Valeur_Et_der12(x); ValDer2 ret2 = F1->Valeur_Et_der12(x); ValDer2 ret; ret.valeur=ponder1*ret1.valeur+ponder2*ret2.valeur; ret.derivee=ponder1*ret1.derivee+ponder2*ret2.derivee; ret.der_sec = ponder1*ret1.der_sec + ponder2*ret2.der_sec; return ret; }; // ramène la dérivée seconde double F1_plus_F2::Der_sec(double x) { ValDer2 ret1 = F2->Valeur_Et_der12(x); ValDer2 ret2 = F1->Valeur_Et_der12(x); return ponder1*ret1.der_sec + ponder2*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_plus_F2::Valeur_stricte(double x) { Valbool ret1 = F2->Valeur_stricte(x); Valbool ret2 = F1->Valeur_stricte(x); Valbool ret; ret.valeur=ponder1*ret1.valeur+ponder2*ret2.valeur; // si un des deux n'est pas dedans le tout n'est pas dedans ret.dedans = ret1.dedans * ret2.dedans; // if ((!ret1.dedans) || (!ret2.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_plus_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=ponder1*ret1.valeur+ponder2*ret2.valeur; ret.derivee=ponder1*ret1.derivee+ponder2*ret2.derivee; ret.dedans = ret1.dedans * ret2.dedans; // 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_plus_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_PLUS_F2") { cout << "\n erreur dans la verification du type de courbe lue "; cout << "\n F1_plus_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_plus_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 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_plus_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; }; }; // ponderations ent >> nom >> ponder1 >> ponder2 ; }; }; // cas donne le niveau de sauvegarde // = 1 : on sauvegarde tout // = 2 : on sauvegarde uniquement les données variables (supposées comme telles) void F1_plus_F2::Ecriture_base_info(ofstream& sort,const int cas) { // on n'a que des grandeurs constantes if (cas == 1) { sort << " F1_PLUS_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 cout << "\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();}; // ponderations sort << "\n ponderations: "<< ponder1 << " "<< ponder2 << " "; }; }; // sortie du schemaXML: en fonction de enu void F1_plus_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; } }; };