diff --git a/ConfigFile.cc b/ConfigFile.cc new file mode 100644 index 0000000000000000000000000000000000000000..34972660e1194200afd7758fbdab2109aab10674 --- /dev/null +++ b/ConfigFile.cc @@ -0,0 +1,482 @@ +/* + * Copyright (C) 2010 Dynare Team + * + * This file is part of Dynare. + * + * Dynare 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. + * + * Dynare 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 Dynare. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <cstdlib> +#include <iostream> +#include <fstream> +#include <vector> + +#include "ConfigFile.hh" +#include <boost/algorithm/string/trim.hpp> +#include <boost/algorithm/string/split.hpp> +#include <boost/lexical_cast.hpp> +using namespace std; + +SlaveNode::SlaveNode(string &computerName_arg, int minCpuNbr_arg, int maxCpuNbr_arg, string &userName_arg, + string &password_arg, string &remoteDrive_arg, string &remoteDirectory_arg, + string &dynarePath_arg, string &matlabOctavePath_arg, bool singleCompThread_arg) : + computerName(computerName_arg), minCpuNbr(minCpuNbr_arg), maxCpuNbr(maxCpuNbr_arg), userName(userName_arg), + password(password_arg), remoteDrive(remoteDrive_arg), remoteDirectory(remoteDirectory_arg), dynarePath(dynarePath_arg), + matlabOctavePath(matlabOctavePath_arg), singleCompThread(singleCompThread_arg) +{ + if (computerName.empty()) + { + cerr << "ERROR: The node must have a ComputerName." << endl; + exit(EXIT_FAILURE); + } +} + +Cluster::Cluster(vector<string> member_nodes_arg) : member_nodes(member_nodes_arg) +{ + if (member_nodes.empty()) + { + cerr << "ERROR: The cluster must have at least one member node." << endl; + exit(EXIT_FAILURE); + } +} + +ConfigFile::ConfigFile(bool parallel_arg, bool parallel_test_arg, + bool parallel_slave_open_mode_arg, const string &cluster_name_arg) : + parallel(parallel_arg), parallel_test(parallel_test_arg), + parallel_slave_open_mode(parallel_slave_open_mode_arg), cluster_name(cluster_name_arg) +{ +} + +ConfigFile::~ConfigFile() +{ +} + +void +ConfigFile::getConfigFileInfo(const string ¶llel_config_file) +{ + if (!parallel && !parallel_test) + return; + + ifstream *configFile; + if (parallel_config_file.empty()) + { + // Test OS and try to open default file +#if defined(_WIN32) || defined(__CYGWIN32__) + string defaultConfigFile (getenv("APPDATA")); + if (&defaultConfigFile==NULL) + { + cerr << "ERROR: APPDATA environment variable not found." << endl; + exit(EXIT_FAILURE); + } + defaultConfigFile += "\\dynare.ini"; +#else + string defaultConfigFile (getenv("HOME")); + if (&defaultConfigFile==NULL) + { + cerr << "ERROR: HOME environment variable not found." << endl; + exit(EXIT_FAILURE); + } + defaultConfigFile += "/.dynare"; +#endif + configFile = new ifstream(defaultConfigFile.c_str(), fstream::in); + if (!configFile->is_open()) + { + cerr << "ERROR: Could not open the default config file" << endl; + exit(EXIT_FAILURE); + } + } + else + { + configFile = new ifstream(parallel_config_file.c_str(), fstream::in); + if (!configFile->is_open()) + { + cerr << "ERROR: Couldn't open file " << parallel_config_file << endl;; + exit(EXIT_FAILURE); + } + } + + string name, computerName, userName, password, remoteDrive, + remoteDirectory, dynarePath, matlabOctavePath; + int minCpuNbr = 0, maxCpuNbr = 0; + bool singleCompThread = true; + vector<string> member_nodes; + + bool inNode = false; + bool inCluster = false; + while (configFile->good()) + { + string line; + getline(*configFile, line); + boost::trim(line); + if (line.empty()) + continue; + + if (!line.compare("[node]") || !line.compare("[cluster]")) + { + addConfFileElement(inNode, inCluster, member_nodes, name, + computerName, minCpuNbr, maxCpuNbr, userName, + password, remoteDrive, remoteDirectory, + dynarePath, matlabOctavePath, singleCompThread); + + //! Reset communication vars / option defaults + if (!line.compare("[node]")) + { + inNode = true; + inCluster = false; + } + else + { + inNode = false; + inCluster = true; + } + + name = userName = computerName = password = remoteDrive = + remoteDirectory = dynarePath = matlabOctavePath = ""; + minCpuNbr = maxCpuNbr = 0; + singleCompThread = true; + member_nodes.clear(); + } + else + { + vector<string> tokenizedLine; + boost::split(tokenizedLine, line, boost::is_any_of("=")); + if (tokenizedLine.size() != 2) + { + cerr << "ERROR (in config file): Options should be formatted as 'option = value'." << endl; + exit(EXIT_FAILURE); + } + boost::trim(tokenizedLine.front()); + boost::trim(tokenizedLine.back()); + + if (!tokenizedLine.front().compare("Name")) + name = tokenizedLine.back(); + else if (!tokenizedLine.front().compare("CPUnbr")) + { + vector<string> tokenizedCpuNbr; + boost::split(tokenizedCpuNbr, tokenizedLine.back(), boost::is_any_of(":")); + try + { + if (tokenizedCpuNbr.size() == 1) + { + minCpuNbr = 1; + maxCpuNbr = boost::lexical_cast< int >(tokenizedCpuNbr.front()); + } + else if (tokenizedCpuNbr.size() == 2 && + tokenizedCpuNbr[0].at(0) == '[' && + tokenizedCpuNbr[1].at(tokenizedCpuNbr[1].size()-1) == ']') + { + tokenizedCpuNbr[0].erase(0,1); + tokenizedCpuNbr[1].erase(tokenizedCpuNbr[1].size()-1,1); + minCpuNbr = boost::lexical_cast< int >(tokenizedCpuNbr[0]); + maxCpuNbr = boost::lexical_cast< int >(tokenizedCpuNbr[1]); + } + } + catch( const boost::bad_lexical_cast & ) + { + cerr << "ERROR: Could not convert value to integer for CPUnbr." << endl; + exit(EXIT_FAILURE); + } + + if (minCpuNbr <= 0 || maxCpuNbr <= 0) + { + cerr << "ERROR: Syntax for the CPUnbr option is as follows:" << endl + << " 1) CPUnbr = <int>" << endl + << " or 2) CPUnbr = [<int>:<int>]" << endl + << " where <int> is an Integer > 0." << endl; + exit(EXIT_FAILURE); + } + + minCpuNbr--; + maxCpuNbr--; + if (minCpuNbr > maxCpuNbr) + { + int tmp = maxCpuNbr; + maxCpuNbr = minCpuNbr; + minCpuNbr = tmp; + } + } + else if (!tokenizedLine.front().compare("ComputerName")) + computerName = tokenizedLine.back(); + else if (!tokenizedLine.front().compare("UserName")) + userName = tokenizedLine.back(); + else if (!tokenizedLine.front().compare("Password")) + password = tokenizedLine.back(); + else if (!tokenizedLine.front().compare("RemoteDrive")) + remoteDrive = tokenizedLine.back(); + else if (!tokenizedLine.front().compare("RemoteDirectory")) + remoteDirectory = tokenizedLine.back(); + else if (!tokenizedLine.front().compare("DynarePath")) + dynarePath = tokenizedLine.back(); + else if (!tokenizedLine.front().compare("MatlabOctavePath")) + matlabOctavePath = tokenizedLine.back(); + else if (!tokenizedLine.front().compare("SingleCompThread")) + if (tokenizedLine.back().compare("true")) + singleCompThread = true; + else if (tokenizedLine.back().compare("false")) + singleCompThread = false; + else + { + cerr << "ERROR (in config file): The value passed to SingleCompThread may only be 'true' or 'false'." << endl; + exit(EXIT_FAILURE); + } + else if (!tokenizedLine.front().compare("Members")) + { + vector<string> tmp_member_nodes; + boost::split(tmp_member_nodes, tokenizedLine.back(), boost::is_any_of(";, ")); + for ( vector<string>::iterator it = tmp_member_nodes.begin(); + it < tmp_member_nodes.end(); it++ ) + { + boost::trim(*it); + if (!it->empty()) + member_nodes.push_back(*it); + } + } + else + { + cerr << "ERROR (in config file): Option " << tokenizedLine.front() << " is invalid." << endl; + exit(EXIT_FAILURE); + } + } + } + + addConfFileElement(inNode, inCluster, member_nodes, name, + computerName, minCpuNbr, maxCpuNbr, userName, + password, remoteDrive, remoteDirectory, + dynarePath, matlabOctavePath, singleCompThread); + configFile->close(); + delete configFile; +} + +void +ConfigFile::addConfFileElement(bool inNode, bool inCluster, vector<string> member_nodes, string &name, + string &computerName, int minCpuNbr, int maxCpuNbr, string &userName, + string &password, string &remoteDrive, string &remoteDirectory, + string &dynarePath, string &matlabOctavePath, bool singleCompThread) +{ + //! ADD NODE + if (inNode) + if (!member_nodes.empty()) + { + cerr << "Invalid option passed to [node]." << endl; + exit(EXIT_FAILURE); + } + else + if (name.empty() || slave_nodes.find(name) != slave_nodes.end()) + { + cerr << "ERROR: Every node must be assigned a unique name." << endl; + exit(EXIT_FAILURE); + } + else + slave_nodes[name] = new SlaveNode(computerName, minCpuNbr, maxCpuNbr, userName, + password, remoteDrive, remoteDirectory, dynarePath, + matlabOctavePath, singleCompThread); + //! ADD CLUSTER + else if (inCluster) + if ( minCpuNbr > 0 || maxCpuNbr > 0 || !userName.empty() || + !password.empty() || !remoteDrive.empty() || !remoteDirectory.empty() || + !dynarePath.empty() || !matlabOctavePath.empty()) + { + cerr << "Invalid option passed to [cluster]." << endl; + exit(EXIT_FAILURE); + } + else + if (name.empty() || clusters.find(name) != clusters.end()) + { + cerr << "ERROR: The cluster must be assigned a unique name." << endl; + exit(EXIT_FAILURE); + } + else + { + if (clusters.empty()) + firstClusterName = name; + clusters[name] = new Cluster(member_nodes); + } +} + +void +ConfigFile::checkPass() const +{ + if (!parallel && !parallel_test) + return; + + //! Check Slave Nodes + if (slave_nodes.empty()) + { + cerr << "ERROR: At least one node must be defined in the config file." << endl; + exit(EXIT_FAILURE); + } + + for (map<string, SlaveNode *>::const_iterator it = slave_nodes.begin(); + it != slave_nodes.end(); it++) + { +#if !defined(_WIN32) && !defined(__CYGWIN32__) + //For Linux/Mac, check that cpuNbr starts at 0 + if (it->second->minCpuNbr != 0) + cout << "WARNING: On Unix-based operating systems, you cannot specify the CPU that is used " + << "in parallel processing. This will be adjusted for you such that the same number of CPUs " + << "are used." << endl; +#endif + if (!it->second->computerName.compare("localhost")) // We are working locally + { + if (!it->second->remoteDrive.empty()) + { + cerr << "ERROR (node " << it->first << "): the RemoteDrive option may not be passed for a local node." << endl; + exit(EXIT_FAILURE); + } + if (!it->second->remoteDirectory.empty()) + { + cerr << "ERROR (node " << it->first << "): the RemoteDirectory option may not be passed for a local node." << endl; + exit(EXIT_FAILURE); + } + } + else + { + if (it->second->userName.empty()) + { + cerr << "ERROR (node " << it->first << "): the UserName option must be passed for every remote node." << endl; + exit(EXIT_FAILURE); + } +#if defined(_WIN32) || defined(__CYGWIN32__) + if (it->second->userName.empty() || it->second->password.empty()) + { + cerr << "ERROR (node " << it->first << "): the Password option must be passed under Windows for every remote node." << endl; + exit(EXIT_FAILURE); + } + if (it->second->remoteDrive.empty()) + { + cerr << "ERROR (node " << it->first << "): the RemoteDrive option must be passed under Windows for every remote node." << endl; + exit(EXIT_FAILURE); + } +#endif + if (it->second->remoteDirectory.empty()) + { + cerr << "ERROR (node " << it->first << "): the RemoteDirectory must be specified for every remote node." << endl; + exit(EXIT_FAILURE); + } + } + } + + //! Check Clusters + if (clusters.empty()) + { + cerr << "ERROR: At least one cluster must be defined in the config file." << endl; + exit(EXIT_FAILURE); + } + + if (!cluster_name.empty() && clusters.find(cluster_name) == clusters.end()) + { + cerr << "ERROR: Cluster Name " << cluster_name << " was not found in the config file." << endl; + exit(EXIT_FAILURE); + } + + for (map<string, Cluster *>::const_iterator it = clusters.begin(); + it != clusters.end(); it++) + for (vector<string>::const_iterator itmn = it->second->member_nodes.begin(); + itmn < it->second->member_nodes.end(); itmn++) + if (slave_nodes.find(*itmn) == slave_nodes.end()) + { + cerr << "Error: node " << *itmn << " specified in cluster " << it->first << " was not found" << endl; + exit(EXIT_FAILURE); + } +} + +void +ConfigFile::transformPass() +{ + if (!parallel && !parallel_test) + return; + +#if !defined(_WIN32) && !defined(__CYGWIN32__) + //For Linux/Mac, check that cpuNbr starts at 0 + for (map<string, SlaveNode *>::const_iterator it = slave_nodes.begin(); + it != slave_nodes.end(); it++) + if (it->second->minCpuNbr != 0) + { + it->second->maxCpuNbr = it->second->maxCpuNbr - it->second->minCpuNbr; + it->second->minCpuNbr = 0; + } +#endif +} + +void +ConfigFile::writeCluster(ostream &output) const +{ + if (!parallel && !parallel_test) + return; + + map<string, Cluster *>::const_iterator cluster_it ; + if (cluster_name.empty()) + cluster_it = clusters.find(firstClusterName); + else + cluster_it = clusters.find(cluster_name); + + int i = 1; + for (map<string, SlaveNode *>::const_iterator it = slave_nodes.begin(); + it != slave_nodes.end(); it++) + { + bool slave_node_in_member_nodes = false; + for (vector<string>::const_iterator itmn = cluster_it->second->member_nodes.begin(); + itmn < cluster_it->second->member_nodes.end(); itmn++) + if (!it->first.compare(*itmn)) + slave_node_in_member_nodes = true; + + if (!slave_node_in_member_nodes) + continue; + + output << "options_.parallel"; + if (i > 1) + output << "(" << i << ")"; + i++; + output << " = struct('Local', "; + if (it->second->computerName.compare("localhost")) + output << "0, "; + else + output << "1, "; + + output << "'ComputerName', '" << it->second->computerName << "', " + << "'CPUnbr', [" << it->second->minCpuNbr << ":" << it->second->maxCpuNbr << "], " + << "'UserName', '" << it->second->userName << "', " + << "'Password', '" << it->second->password << "', " + << "'RemoteDrive', '" << it->second->remoteDrive << "', " + << "'RemoteDirectory', '" << it->second->remoteDirectory << "', " + << "'DynarePath', '" << it->second->dynarePath << "', " + << "'MatlabOctavePath', '" << it->second->matlabOctavePath << "', "; + + if (it->second->singleCompThread) + output << "'SingleCompThread', 'true');" << endl; + else + output << "'SingleCompThread', 'false');" << endl; + } + + if (parallel_slave_open_mode) + output << "options_.parallel_info.leaveSlaveOpen = 1;" << endl; + + output << "InitializeComputationalEnvironment();" << endl; + if (parallel_test) + output << "ErrorCode = AnalyseComputationalEnvironment(options_.parallel, options_.parallel_info);" << endl + << "disp(['AnalyseComputationalEnvironment returned with Error Code: ' num2str(ErrorCode)]);" << endl + << "diary off;" << endl + << "return;" << endl; +} + +void +ConfigFile::writeEndParallel(ostream &output) const +{ + if ((!parallel && !parallel_test) || !parallel_slave_open_mode) + return; + + output << "if options_.parallel_info.leaveSlaveOpen == 1" << endl + << " closeSlave(options_.parallel,options_.parallel_info.RemoteTmpFolder);" << endl + << "end" << endl; +} diff --git a/ConfigFile.hh b/ConfigFile.hh new file mode 100644 index 0000000000000000000000000000000000000000..1a5eb9974c4f4dec77c8126e1ddb0c9c97ba4f9e --- /dev/null +++ b/ConfigFile.hh @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2010 Dynare Team + * + * This file is part of Dynare. + * + * Dynare 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. + * + * Dynare 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 Dynare. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _CONFIG_FILE_HH +#define _CONFIG_FILE_HH + +#include <map> +#include <vector> +using namespace std; + +class SlaveNode +{ + friend class ConfigFile; +public: + SlaveNode(string &computerName_arg, int minCpuNbr_arg, int maxCpuNbr_arg, string &userName_arg, + string &password_arg, string &remoteDrive_arg, string &remoteDirectory_arg, + string &dynarePath_arg, string &matlabOctavePath_arg, bool singleCompThread_arg); + ~SlaveNode(); + +protected: + const string computerName; + int minCpuNbr; + int maxCpuNbr; + const string userName; + const string password; + const string remoteDrive; + const string remoteDirectory; + const string dynarePath; + const string matlabOctavePath; + const bool singleCompThread; +}; + +class Cluster +{ + friend class ConfigFile; +public: + Cluster(vector<string> member_nodes_arg); + ~Cluster(); + +protected: + const vector<string> member_nodes; +}; + +//! The abstract representation of a "config" file +class ConfigFile +{ +public: + ConfigFile(bool parallel_arg, bool parallel_test_arg, bool parallel_slave_open_mode_arg, const string &cluster_name); + ~ConfigFile(); + +private: + const bool parallel; + const bool parallel_test; + const bool parallel_slave_open_mode; + const string cluster_name; + string firstClusterName; + //! Cluster Table + map<string, Cluster *> clusters; + //! Node Map + map<string, SlaveNode *> slave_nodes; + //! Add a SlaveNode or a Cluster object + void addConfFileElement(bool inNode, bool inCluster, vector<string> member_nodes, string &name, + string &computerName, int minCpuNbr, int maxCpuNbr, string &userName, + string &password, string &remoteDrive, string &remoteDirectory, + string &dynarePath, string &matlabOctavePath, bool singleCompThread); +public: + //! Parse config file + void getConfigFileInfo(const string ¶llel_config_file); + //! Check Pass + void checkPass() const; + //! Check Pass + void transformPass(); + //! Create options_.parallel structure, write options + void writeCluster(ostream &output) const; + //! Close slave nodes if needed + void writeEndParallel(ostream &output) const; +}; + +#endif // ! CONFIG_FILE_HH diff --git a/DynareMain.cc b/DynareMain.cc index 8969aaadf0768b7b331d84471f3b4fd6eabe80f4..27225bfa61be20c64a7fdde053c63d9eebdf679a 100644 --- a/DynareMain.cc +++ b/DynareMain.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2009 Dynare Team + * Copyright (C) 2003-2010 Dynare Team * * This file is part of Dynare. * @@ -34,7 +34,9 @@ using namespace std; Splitting main() in two parts was necessary because ParsingDriver.h and MacroDriver.h can't be included simultaneously (because of Bison limitations). */ -void main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tmp_terms, bool warn_uninit +void main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tmp_terms, bool warn_uninit, + bool parallel, const string ¶llel_config_file, const string &cluster_name, bool parallel_slave_open_mode, + bool parallel_test #if defined(_WIN32) || defined(__CYGWIN32__) , bool cygwin, bool msvc #endif @@ -44,6 +46,7 @@ void usage() { cerr << "Dynare usage: dynare mod_file [debug] [noclearall] [savemacro[=macro_file]] [onlymacro] [nolinemacro] [notmpterms] [warn_uninit]" + << " [parallel[=cluster_name]] [conffile=parallel_config_path_and_filename] [parallel_slave_open_mode] [parallel_test]" #if defined(_WIN32) || defined(__CYGWIN32__) << " [cygwin] [msvc]" #endif @@ -72,6 +75,11 @@ main(int argc, char **argv) bool cygwin = false; bool msvc = false; #endif + string parallel_config_file; + bool parallel = false; + string cluster_name; + bool parallel_slave_open_mode = false; + bool parallel_test = false; // Parse options for (int arg = 2; arg < argc; arg++) @@ -107,6 +115,32 @@ main(int argc, char **argv) else if (!strcmp(argv[arg], "msvc")) msvc = true; #endif + else if (strlen(argv[arg]) >= 8 && !strncmp(argv[arg], "conffile", 8)) + { + if (strlen(argv[arg]) <= 9 || argv[arg][8] != '=') + { + cerr << "Incorrect syntax for conffile option" << endl; + usage(); + } + parallel_config_file = string(argv[arg] + 9); + } + else if (!strcmp(argv[arg], "parallel_slave_open_mode")) + parallel_slave_open_mode = true; + else if (!strcmp(argv[arg], "parallel_test")) + parallel_test = true; + else if (strlen(argv[arg]) >= 8 && !strncmp(argv[arg], "parallel", 8)) + { + parallel = true; + if (strlen(argv[arg]) > 8) + { + if (strlen(argv[arg]) == 9 || argv[arg][8] != '=') + { + cerr << "Incorrect syntax for parallel option" << endl; + usage(); + } + cluster_name = string(argv[arg] + 9); + } + } else { cerr << "Unknown option: " << argv[arg] << endl; @@ -146,7 +180,8 @@ main(int argc, char **argv) return EXIT_SUCCESS; // Do the rest - main2(macro_output, basename, debug, clear_all, no_tmp_terms, warn_uninit + main2(macro_output, basename, debug, clear_all, no_tmp_terms, warn_uninit, + parallel, parallel_config_file, cluster_name, parallel_slave_open_mode, parallel_test #if defined(_WIN32) || defined(__CYGWIN32__) , cygwin, msvc #endif diff --git a/DynareMain2.cc b/DynareMain2.cc index 1090685139ea76676d36850a49397f452531776c..5b944a4ace5fa38dc9cd805ec99721b054619246 100644 --- a/DynareMain2.cc +++ b/DynareMain2.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Dynare Team + * Copyright (C) 2008-2010 Dynare Team * * This file is part of Dynare. * @@ -23,9 +23,12 @@ using namespace std; #include "ParsingDriver.hh" #include "ModFile.hh" +#include "ConfigFile.hh" void -main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tmp_terms, bool warn_uninit +main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tmp_terms, bool warn_uninit, + bool parallel, const string ¶llel_config_file, const string &cluster_name, bool parallel_slave_open_mode, + bool parallel_test #if defined(_WIN32) || defined(__CYGWIN32__) , bool cygwin, bool msvc #endif @@ -35,12 +38,16 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tm // Do parsing and construct internal representation of mod file ModFile *mod_file = p.parse(in, debug); + ConfigFile config_file (parallel, parallel_test, parallel_slave_open_mode, cluster_name); + config_file.getConfigFileInfo(parallel_config_file); // Run checking pass mod_file->checkPass(); + config_file.checkPass(); // Perform transformations on the model (creation of auxiliary vars and equations) mod_file->transformPass(); + config_file.transformPass(); // Evaluate parameters initialization, initval, endval and pounds mod_file->evalAllExpressions(warn_uninit); @@ -49,7 +56,7 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tm mod_file->computingPass(no_tmp_terms); // Write outputs - mod_file->writeOutputFiles(basename, clear_all + mod_file->writeOutputFiles(basename, clear_all, config_file #if defined(_WIN32) || defined(__CYGWIN32__) , cygwin, msvc #endif diff --git a/Makefile.am b/Makefile.am index 8c80d0d806fdf5de167276819cc41f6276f49961..d1f6b272a0bf3cf22dae62fdd00653189e4ff973 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,6 +36,8 @@ dynare_m_SOURCES = \ DataTree.hh \ ModFile.cc \ ModFile.hh \ + ConfigFile.cc \ + ConfigFile.hh \ Statement.cc \ Statement.hh \ ExprNode.cc \ diff --git a/ModFile.cc b/ModFile.cc index e97f5ff51c8fe9e78bd9475beaecb45c176adcbe..bf6b9130fa2990271a5babf0c03552e21f8b168b 100644 --- a/ModFile.cc +++ b/ModFile.cc @@ -22,6 +22,7 @@ #include <fstream> #include <typeinfo> #include "ModFile.hh" +#include "ConfigFile.hh" ModFile::ModFile() : expressions_tree(symbol_table, num_constants, external_functions_table), dynamic_model(symbol_table, num_constants, external_functions_table), @@ -344,7 +345,7 @@ ModFile::computingPass(bool no_tmp_terms) } void -ModFile::writeOutputFiles(const string &basename, bool clear_all +ModFile::writeOutputFiles(const string &basename, bool clear_all, const ConfigFile &config_file #if defined(_WIN32) || defined(__CYGWIN32__) , bool cygwin, bool msvc #endif @@ -419,6 +420,8 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all << "options_.bytecode=" << byte_code << ";" << endl << "options_.use_dll=" << use_dll << ";" << endl; + config_file.writeCluster(mOutputFile); + if (byte_code) mOutputFile << "if exist('bytecode') ~= 3" << endl << " error('DYNARE: Can''t find bytecode DLL. Please compile it or remove the ''bytecode'' option.')" << endl @@ -530,8 +533,11 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all if (block && !byte_code) mOutputFile << "rmpath " << basename << ";" << endl; - mOutputFile << "save('" << basename << "_results.mat', 'oo_', 'M_', 'options_');" << endl - << "diary off" << endl + mOutputFile << "save('" << basename << "_results.mat', 'oo_', 'M_', 'options_');" << endl; + + config_file.writeEndParallel(mOutputFile); + + mOutputFile << "diary off" << endl << endl << "disp(['Total computing time : ' dynsec2hms(toc) ]);" << endl; mOutputFile.close(); diff --git a/ModFile.hh b/ModFile.hh index a9f354dbfd98936a02e6e06c656dc249f62b4552..71d363167aaee70a5df65797193be64dfa24e69f 100644 --- a/ModFile.hh +++ b/ModFile.hh @@ -33,6 +33,7 @@ using namespace std; #include "SteadyStateModel.hh" #include "Statement.hh" #include "ExternalFunctionsTable.hh" +#include "ConfigFile.hh" //! The abstract representation of a "mod" file class ModFile @@ -106,7 +107,7 @@ public: \param clear_all Should a "clear all" instruction be written to output ? \param msvc Should the MEX command of use_dll be adapted for MSVC? */ - void writeOutputFiles(const string &basename, bool clear_all + void writeOutputFiles(const string &basename, bool clear_all, const ConfigFile &config_file #if defined(_WIN32) || defined(__CYGWIN32__) , bool cygwin, bool msvc #endif