// 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 "LesFonctions_nD.h" #include "ParaGlob.h" //#include #include "CharUtil.h" // --------------- variables statiques --------- MotCle LesFonctions_nD::motCle; // liste des mots clés LesFonctions_nD::LesFonctions_nD(const LesCourbes1D* lesC1) : // par defaut listeDeFonction_nD(),lesCourbes1D(lesC1) { }; // DESTRUCTEUR : LesFonctions_nD::~LesFonctions_nD () { // effacement des grandeurs pointées par la liste de référence map < string, Fonction_nD * , std::less >::iterator i,ifin=listeDeFonction_nD.end(); for (i=listeDeFonction_nD.begin() ; i != ifin; i++) if ((*i).second != NULL) delete (*i).second; }; // changement du pointeur sur LesCourbes1D: prévu une seule fois // sinon cela veut dire que lesCourbes1D n'est pas un singleton !! // donc n'est possible que si lesCourbes1D n'a pas été attribué // ok également si c'est le même pointeur qui est déjà enregistré void LesFonctions_nD::Attribut_pointeur_lesCourbes1D(const LesCourbes1D * lesC1) { if (lesCourbes1D == NULL) {lesCourbes1D = lesC1;} else if (lesCourbes1D != lesC1) {cout << "\n *** erreur d'affectation du pointeur interne sur les courbes 1D " << " le pointeur est deja affecte ... " << "\n LesFonctions_nD::Attribut_pointeur_lesCourbes1D( " << endl; Sortie(1); }; }; // lecture des fonctions void LesFonctions_nD::Lecture(UtilLecture & entreePrinc) { if (strstr(entreePrinc.tablcar,"les_fonctions_nD")!=NULL) {try { if (ParaGlob::NiveauImpression() >= 4) cout << " debut de la lecture de fonctions " << endl; // lecture des fonctions temps qu'il n'y a pas de nouveau mot clé string nom_fonction,type_fonction; // variables de travail Fonction_nD * fonction=NULL; entreePrinc.NouvelleDonnee(); while (!motCle.SimotCle(entreePrinc.tablcar)) { // lecture du nom de la fonction et de son type *(entreePrinc.entree) >> nom_fonction >> type_fonction; if (ParaGlob::NiveauImpression() >= 6) cout << " lecture de la fonction " << nom_fonction << endl; // création de la fonction fonction = Fonction_nD::New_Fonction_nD(nom_fonction,Id_Nom_Fonction_nD (type_fonction.c_str())); // lecture de la fonction fonction->LectDonnParticulieres_Fonction_nD (nom_fonction,&entreePrinc); if (ParaGlob::NiveauImpression() >= 6) cout << " fin de la lecture de la fonction " << nom_fonction << endl; // verification que l'on n'a pas deux noms de fonctions identiques bool res = false; map < string, Fonction_nD * , std::less > ::iterator il = listeDeFonction_nD.find(nom_fonction); if (il != listeDeFonction_nD.end()) res=true; if (res) { cout <<" \n Erreur de lecture de fonctions nD, deux fonctions ont le meme nom \n"; cout <<" nom = " << nom_fonction << '\n'; cout <<"LesFonctions_nD::LectureLesFonctions_nD(UtilLecture & entreePrinc)" << endl; entreePrinc.MessageBuffer("lecture des fonctions nD"); throw (UtilLecture::ErrNouvelleDonnee(-1)); Sortie (1); } else listeDeFonction_nD[nom_fonction]=fonction; entreePrinc.NouvelleDonnee(); // nouvelle ligne }; if (ParaGlob::NiveauImpression() >= 4) cout << " fin de la lecture de fonctions " << endl; } catch (ErrSortieFinale) // cas d'une direction voulue vers la sortie // on relance l'interuption pour le niveau supérieur { ErrSortieFinale toto; throw (toto); } catch(...) { cout << "\n ** erreur en lecture d'une fonction nD "; throw (UtilLecture::ErrNouvelleDonnee(-1)); Sortie(1); }; }; // maintenant on établit les liens éventuels entres les fonctions qui peuvent dépendre les unes des autres // (exemple de fonction complexe construite à partir de fonction simples) // on boucle tant que les fonctions ne sont pas complète // avec un maxi de boucles arbitraires int max_boucle = 100; int ib = 1; bool complet_fonction = false; bool affichage = false; map < string, Fonction_nD * , std::less >::iterator idl,edlfin=listeDeFonction_nD.end(); while (!complet_fonction && (ib < max_boucle)) {for (idl = listeDeFonction_nD.begin();idl != edlfin;idl++) {Fonction_nD * co = (*idl).second; // pour plus de clarté if (co->DependAutreFoncCourbes()) {// === cas d'une fonction avec dépendance à d'autres fonctions // -- récupération des noms de fonctions de dépendance list lico; co->ListDependanceFonctions(lico); // -- création de la liste de pointeur de fonctions correspondantes list ::iterator ili,ilifin=lico.end(); list liptco; bool liste_de_fct_complete = true; for (ili=lico.begin();ili!=ilifin;ili++) {//if (liptco->complet()) liptco.push_back(LesFonctions_nD::Trouve(*ili)); }; // === cas d'une fonction avec dépendance à des courbes // -- récupération des noms de fonctions de dépendance list licourbe; co->ListDependanceCourbes(licourbe); // -- création de la liste de pointeur de courbes correspondantes list liptcourbe; // for (string & nom : licourbe) // liptcourbe.push_back(lesCourbes1D->Trouve(nom)); {list ::iterator kk,kkfin=licourbe.end(); for (kk=licourbe.begin();kk != kkfin;kk++) liptcourbe.push_back(lesCourbes1D->Trouve(*kk)); }; // ---- on renseigne la fonction co->Lien_entre_fonc_courbe(liptco,liptcourbe); }; }; // on fait un passage pour voir si les fonctions sont complètes complet_fonction = true; // bon par défaut for (idl = listeDeFonction_nD.begin();idl != edlfin;idl++) {Fonction_nD * co = (*idl).second; // pour plus de clarté if (!(co->Complet_Fonction())) {complet_fonction = false; break; } }; ib++; }; // si ib > max_boucle c'est cuit if (ib >= max_boucle) { cout << "\n *** erreur en lectue des fonctions nD " << " on n'a pas reussi a associer les courbes dependantes les unes des autres" << "\n LesFonctions_nD::Lecture(..."< list_enuFonction_nD = Fonction_nD::Liste_Fonction_disponible(); // affichage et choix de fonction nD cout << "\n Donner le type de fonction que vous souhaitez utiliser: ? " << "\n (NB: l'utilitaire va definir un exemple de fonction qu'il faudra ensuite adapter !) ";; string rep;int num; bool choix_valide = false; Tableau chooi(list_enuFonction_nD.size(),false); // tableau de travail list nom_de_fichiers; bool inclusion_fichier=false; list ::iterator it,itfin=list_enuFonction_nD.end(); while (!choix_valide) { try { // affichage des éléments possibles int undeux=0; cout << "\n (0 ou f) fin \n"; int inu; for (it=list_enuFonction_nD.begin(),inu=1;it!=itfin;it++,inu++) { cout << "\n"; cout << " (" << inu << ") " << Nom_Fonction_nD(*it) << " "; //undeux++; //if (undeux==2) {cout << "\n";undeux=0;} }; int nb_fonction = list_enuFonction_nD.size(); cout << "\n (" << nb_fonction+1 << ") inclusion d'un fichier de def de fonction "; cout << "\n un numero ? "; rep = lect_return_defaut(false,"f"); if (rep == "fin_prog") Sortie(1); num = ChangeEntier(rep); if (Minuscules(rep) == "f") num = 0; choix_valide=false; if (num == 0) { choix_valide=true;} else if (num == nb_fonction+1) { string nom_fichier=""; cout << "\n nom du fichier ? "; nom_fichier=lect_chaine(); cout << " nom lu: "<= 0)&&(num<=list_enuFonction_nD.size())) {if (chooi(num)) cout << "\n type d'element deja choisit, recommencer" << endl; else chooi(num) = true; } else { cout << "\n Erreur on attendait un entier entre 0 et "<< list_enuFonction_nD.size()+1 <<" !!, " << "\n redonnez une bonne valeur" << "\n ou taper fin_prog pour arreter le programme"; }; }; } catch (ErrSortieFinale) // cas d'une direction voulue vers la sortie // on relance l'interuption pour le niveau supérieur { ErrSortieFinale toto; throw (toto); } catch (...)//(UtilLecture::ErrNouvelleDonnee erreur) { cout << "\n Erreur on attendait un entier entre 0 et "<< list_enuFonction_nD.size() <<" !!, " << "\n redonnez une bonne valeur" << "\n ou taper fin_prog pour arreter le programme"; choix_valide=false; } } //-- fin du while // maintenant on définit un exemplaire de chaque fonction choisit int cot=1;string nom_fonction; Fonction_nD * fonction=NULL; for (it=list_enuFonction_nD.begin();it!=itfin;it++,cot++) { if(chooi(cot)) { nom_fonction = "exemple_fonction"; nom_fonction += ChangeEntierSTring(cot); fonction = Fonction_nD::New_Fonction_nD(nom_fonction,*it); listeDeFonction_nD[nom_fonction]=fonction; } } // affichage des infos dans le fichier de commande ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier sort << "\n#----------------------------------------" << "\n# definition facultative de fonction nD|" << "\n#----------------------------------------" << "\n \n les_fonctions_nD #------------" << endl; // puis chaque fonction sort ses infos map < string, Fonction_nD * , std::less >::iterator itc,itcfin = listeDeFonction_nD.end(); for (itc= listeDeFonction_nD.begin();itc!=itcfin;itc++) (*itc).second->Info_commande_Fonctions_nD(entreePrinc); // dans le cas où il y a des inclusions de fichiers if (inclusion_fichier) { list ::iterator ill,illfin = nom_de_fichiers.end(); for (ill=nom_de_fichiers.begin();ill != illfin;ill++) sort << "\n < " << (*ill) ; }; // fin def fonction sort << "\n#------------- fin def des fonctions nD ------------------------" << endl; sort << flush; }; }; // affichage des fonctions void LesFonctions_nD::Affiche() const { map < string, Fonction_nD * , std::less >::const_iterator i,ifin=listeDeFonction_nD.end(); cout << " \n ------- affichage des listes de fonctions ------- \n "; cout << "\n nombre= " << listeDeFonction_nD.size() ; for (i=listeDeFonction_nD.begin() ; i != ifin; i++) { // on écrit le nom de la fonction et de sont type, sous forme énuméré, car ensuite dans chaque fonction le nom en string est écrit cout << "\n" << (*i).first << " " << ((*i).second)->Type_Fonction(); ((*i).second)->Affiche(); } cout << endl; }; // test si la fonction de nom st1 existe reellement // retourne false si n'existe pas , true sinon bool LesFonctions_nD::Existe(const string & st1) const { // verification bool res = false; map < string, Fonction_nD *, std::less > ::const_iterator il = listeDeFonction_nD.find(st1); if (il != listeDeFonction_nD.end()) res=true; return res; }; // retourne la fonction correspondant a une cle Fonction_nD* LesFonctions_nD::Trouve(const string & st1) const { map < string, Fonction_nD *, std::less > ::const_iterator il = listeDeFonction_nD.find(st1); if (il != listeDeFonction_nD.end()) return ((*il).second); cout << " \n pb la fonction nD de nom " << st1 << " n\'existe pas !! " << endl; Sortie (1); Fonction_nD* bidon=NULL ; // pour ne pas avoir de message de warning return bidon; }; // vérification que tout est ok, pres à l'emploi // ramène true si ok, false sinon bool LesFonctions_nD::Complet() { // on passe en revue toutes les fonctions map < string, Fonction_nD *, std::less > ::const_iterator il, ilfin = listeDeFonction_nD.end(); bool retour = true; for (il=listeDeFonction_nD.begin();il!=ilfin;il++) { // on en profite pour mettre à jour les variables globales ((*il).second)->Mise_a_jour_variables_globales(); // puis on vérifie bool ret=((*il).second)->Complet_Fonction(); if (!ret) { cout << "\n erreur!!! la fonction n'est pas complete"; ((*il).second)->Affiche(); retour = false; } } return retour; }; // utilitaire pour lire une fonction, soit qui ne sera pas stocké par LesFonctions_nD // dans ce cas sont nom est "_", soit son nom correspond à une ref de nom de fonctions existante // dans tous les cas on lit un nom et un type de fonction c-a-d un string et un EnumFonction_nD // ----- différents cas ------- // ptfonction: soit == NULL, : on lit un nom, et on lit un type de fonction // 1) si celui-ci est "_", cela signifie que la fonction à lire // est interne à l'utilisateur, on crée une fonction, on lit la fonction // avec Lecture_base_info de la fonction et on ramène un pointeur sur la // nouvelle fonction // 2) si celui-ci est différent de "_", c'est une référence de fonction // on lit la référence et on ramène un pointeur sur la fonction de // LesFonctions_nD correspondant // // soit == une fonction existante: on lit un nom, et on regarde le nom actuel de la fonction pointée // par ptfonction que l'on appelera nom_ref // 1) nom = "_" et nom_ref = "_" // 1-a les deux fonctions sont du même type on relie les données avec Lecture_base_info // et on ramène ptfonction // 1-b les deux fonctions sont de type différent, on supprime la fonction pointée par // ptfonction, on en crée une nouvelle adoc, et on ramène un pointeur dessus // 2) nom != "_" et nom_ref == "_" // la fonctions pointé par ptfonction est supprimé, et on associe le pointeur de retour // a la fonction correspondant à nom de LesFonctions_nD // 3) nom == "_" et nom_ref != "_" // on crée une nouvelle fonction adoc, on lie avec Lecture_base_info, et on ramène // un pointeur sur la fonction ainsi crée Fonction_nD * LesFonctions_nD::Lecture_pour_base_info(ifstream& ent,const int cas,Fonction_nD * ptfonction) { EnumFonction_nD type_de_fonction;string nom_fonction; ent >> nom_fonction >> type_de_fonction; if (ptfonction == NULL) {if (nom_fonction == "_") {// cas d'une fonction interne à l'appelant et pas de fonction défini, on en définit une ptfonction = Fonction_nD::New_Fonction_nD(nom_fonction,type_de_fonction); // lecture des infos ptfonction->Lecture_base_info(ent,cas); } else {// cas d'une référence de fonction if (this->Existe(nom_fonction)) { ptfonction = this->Trouve(nom_fonction);} else {cout << "\n erreur 1 en lecture de la fonction de nom " << nom_fonction << " elle n'existe pas dans la liste des fonctions avec reference" << "\n LesFonctions_nD::Lecture_pour_base_info(..."; Sortie(1); } }; } else { // cas où une fonction est déjà pointé if ((ptfonction->NomFonction() == "_") && (nom_fonction == "_")) { if (type_de_fonction == ptfonction->Type_Fonction()) {// même type on se contente de relire ptfonction->Lecture_base_info(ent,cas); } else {// pas de même type on supprime, on recrée, on li delete ptfonction; ptfonction = Fonction_nD::New_Fonction_nD(nom_fonction,type_de_fonction); ptfonction->Lecture_base_info(ent,cas); } } else if ((ptfonction->NomFonction() == "_") && (nom_fonction != "_")) { // l'ancien est interne et le nouveau est une ref, on supprime, on récup la ref delete ptfonction; if (this->Existe(nom_fonction)) { ptfonction = this->Trouve(nom_fonction);} else {cout << "\n erreur 2 en lecture de la fonction de nom " << nom_fonction << " elle n'existe pas dans la liste des fonctions avec reference" << "\n LesFonctions_nD::Lecture_pour_base_info(..."; Sortie(1); } } else if ((ptfonction->NomFonction() != "_") && (nom_fonction == "_")) { // l'ancien est une ref et le nouveau est interne, on crée et on li ptfonction = Fonction_nD::New_Fonction_nD(nom_fonction,type_de_fonction); ptfonction->Lecture_base_info(ent,cas); } } //-- fin du cas ou ptfonction != NULL // retour du pointeur return ptfonction; }; // écriture pour base info // c'est le pendant de Lecture_pour_base_info, de manière à être cohérent void LesFonctions_nD::Ecriture_pour_base_info(ofstream& sort,const int cas,Fonction_nD * ptfonction) { // la fonction d'écrouissage sort << ptfonction->NomFonction() << " " << ptfonction->Type_Fonction() << " "; // écriture le la fonction elle-même que si le nom est "_" if (ptfonction->NomFonction() == "_") {ptfonction->Ecriture_base_info(sort,cas);}; }; //----- lecture écriture de base info ----- // lecture base info // = 1 : on récupère tout // = 2 : on récupère uniquement les données variables (supposées comme telles) void LesFonctions_nD::Lecture_base_info(ifstream& entr,const int cas) {if (cas == 1) {cout << " == lecture des fonctions \n"; string toto;int taille; entr >> toto >> taille ; // passage de l'entête // on boucle sur le nombre de fonction à lire EnumFonction_nD type_de_fonction; // " Fonction_nD* fonction; string nom_fonction; string type_fonction; // " for (int i=1;i<= taille; i++) { // lecture du nom de la fonction et de son type entr >> nom_fonction >> type_de_fonction; // création de la fonction fonction = Fonction_nD::New_Fonction_nD(nom_fonction,type_de_fonction); // lecture de la fonction fonction->Lecture_base_info(entr,cas); // verification que l'on n'a pas deux noms de fonctions identiques bool res = false; map < string, Fonction_nD* , std::less > ::iterator il = listeDeFonction_nD.find(nom_fonction); if (il != listeDeFonction_nD.end()) res=true; if (res) { cout <<" \n Erreur de lecture de fonctions nD, deux fonctions ont le meme nom \n"; cout <<" nom = " << nom_fonction << '\n'; cout <<"LesFonctions_nD::Lecture_base_info(..." << endl; Sortie (1); } else // intégration dans la liste listeDeFonction_nD[nom_fonction]=fonction; }; // maintenant on établit les liens éventuels entres les fonctions qui peuvent dépendre les unes des autres // (exemple de fonction complexe construite à partir de fonction simples) // --- on suit la même procédure que dans Lecture() map < string, Fonction_nD * , std::less >::iterator idl,edlfin=listeDeFonction_nD.end(); for (idl = listeDeFonction_nD.begin();idl != edlfin;idl++) {Fonction_nD * co = (*idl).second; // pour plus de clarté if (co->DependAutreFoncCourbes()) {// === cas d'une fonction avec dépendance à d'autres fonctions // -- récupération des noms de fonctions de dépendance list lico; co->ListDependanceFonctions(lico); // -- création de la liste de pointeur de fonctions correspondantes list ::iterator ili,ilifin=lico.end(); list liptco; for (ili=lico.begin();ili!=ilifin;ili++) liptco.push_back(LesFonctions_nD::Trouve(*ili)); // === cas d'une fonction avec dépendance à des courbes // -- récupération des noms de fonctions de dépendance list licourbe; co->ListDependanceCourbes(licourbe); // -- création de la liste de pointeur de courbes correspondantes list liptcourbe; // for (string & nom : licourbe) // liptcourbe.push_back(lesCourbes1D->Trouve(nom)); {list ::iterator kk,kkfin=licourbe.end(); for (kk=licourbe.begin();kk != kkfin;kk++) liptcourbe.push_back(lesCourbes1D->Trouve(*kk)); }; // ---- on renseigne la fonction co->Lien_entre_fonc_courbe(liptco,liptcourbe); }; }; }; }; // écriture base info // = 1 : on sauvegarde tout // = 2 : on sauvegarde uniquement les données variables (supposées comme telles) void LesFonctions_nD::Ecriture_base_info(ofstream& sort,const int cas) { if (cas == 1) {sort << "\n \n****les_fonctions_nD_:_nombre= " << listeDeFonction_nD.size() ; // on balaie la liste map < string, Fonction_nD* , std::less >::iterator i,ifin=listeDeFonction_nD.end(); for (i=listeDeFonction_nD.begin() ; i != ifin; i++) { // on écrit le nom de la fonction et de sont type, sous forme énuméré, car ensuite dans chaque fonction le nom // en string est écrit sort << "\n" << (*i).first << " " << ((*i).second)->Type_Fonction(); // puis écriture de la fonction ((*i).second)->Ecriture_base_info(sort,cas); } } sort << "\n"; }; // sortie du schemaXML: en fonction de enu void LesFonctions_nD::SchemaXML_lesFonctions_nD(ofstream& sort,const Enum_IO_XML enu) { switch (enu) {case XML_TYPE_GLOBAUX: // cas du premier passage {// cas des classes de base, on commence par créé la liste globale des fonctions possible // on récupère la liste des identificateurs de fonctions actuellement disponible list list_enuFonction_nD = Fonction_nD::Liste_Fonction_disponible(); // maintenant on définit un exemplaire de chaque fonction possible list ::iterator it,itfin=list_enuFonction_nD.end(); int cot=1;string nom_fonction; Fonction_nD * fonction=NULL; for (it=list_enuFonction_nD.begin();it!=itfin;it++,cot++) { nom_fonction = "exemple_fonction"; nom_fonction += ChangeEntierSTring(cot); fonction = Fonction_nD::New_Fonction_nD(nom_fonction,*it); listeDeFonction_nD[nom_fonction]=fonction; }; break; } case XML_IO_POINT_INFO: {// cas de def de LesMaillages /* sort << "\n" << "\n " << "\n " << "\n " << "\n " << "\n";*/ // def de Maillage // SchemaXML_Maillage(sort,niveau); break; } }; // on balaie l'ensemble des fonctions map < string, Fonction_nD * , std::less >::iterator itc,itcfin = listeDeFonction_nD.end(); for (itc= listeDeFonction_nD.begin();itc!=itcfin;itc++) (*itc).second->SchemaXML_Fonctions_nD(sort,enu); };