gambit is hosted by Hepforge, IPPP Durham
GAMBIT  v1.5.0-252-gf9a3f78
a Global And Modular Bsm Inference Tool
yaml_parser_base.cpp
Go to the documentation of this file.
1 // GAMBIT: Global and Modular BSM Inference Tool
2 // *********************************************
20 
21 #include <iostream>
22 
26 #include "gambit/Logs/logger.hpp"
28 
29 
30 namespace Gambit
31 {
32 
33  namespace IniParser
34  {
35 
37  int importRound(YAML::Node node, const std::string& filename)
38  {
39  int counter = 0;
40  if (node.IsScalar())
41  {
42  if ( node.Tag() == "!import" )
43  {
44  #ifdef WITH_MPI
45  int rank = GMPI::Comm().Get_rank();
46  #else
47  int rank = 0;
48  #endif
49  YAML::Node import;
50  std::string new_filename = node.as<std::string>();
51  if (rank == 0) std::cout << "Importing: " << new_filename << std::endl;
52  try
53  {
54  // We want to do the import relative to the path in which the YAML file
55  // sits, unless it has a forward slash at the beginning (in which case we
56  // will interpret it as an absolute path)
57  std::string file_location = Utils::dir_name(filename); // "outer" file location
58  if(new_filename.at(0)=='/') // POSIX
59  {
60  // Use the absolute path as given
61  import = YAML::LoadFile(new_filename);
62  }
63  else
64  {
65  // Append the path of the outer file
66  new_filename = file_location+"/"+new_filename;
67  import = YAML::LoadFile(new_filename);
68  }
69  }
70  catch (YAML::Exception &e)
71  {
72  std::ostringstream msg;
73  msg << "Error importing \""<<new_filename<<"\"! ";
74  msg << "Please check that file exists! Error occurred during parsing of YAML file '"<<filename<<"'" << endl;
75  msg << "(yaml-cpp error: "<<e.what()<<" )";
76  inifile_error().raise(LOCAL_INFO,msg.str());
77  }
78  node = import;
79  return 1;
80  }
81  return 0;
82  }
83  if (node.IsSequence())
84  {
85  for (unsigned int i = 0; i<node.size(); ++i)
86  {
87  counter += importRound(node[i],filename);
88  }
89  return counter;
90  }
91  if (node.IsMap())
92  {
93  for (YAML::const_iterator it = node.begin(); it != node.end(); ++it)
94  {
95  counter += importRound(it->second,filename); // Only values are processed
96  }
97  return counter;
98  }
99  return 0;
100  }
101 
102  void recursiveImport(const YAML::Node& node, const std::string& filename)
103  {
104  int import_counter = 0;
105  int last_import_counter = 0;
106  for ( int i = 0; i < 10; ++i)
107  {
108  last_import_counter = importRound(node,filename);
109  import_counter += last_import_counter;
110  }
111  if (last_import_counter > 0)
112  {
113  #ifdef WITH_MPI
114  int rank = GMPI::Comm().Get_rank();
115  #else
116  int rank = 0;
117  #endif
118  if (rank == 0)
119  {
120  std::cout << last_import_counter << std::endl;
121  std::cout << "WARNING: YAML imports were truncated after 10 recursions." << std::endl;
122  }
123  }
124  }
125 
126 
127  // Implementations of main inifile class
128 
129  void Parser::readFile(std::string filename)
130  {
131  YAML::Node root = filename_to_node(filename);
132  basicParse(root,filename);
133  }
134 
135  YAML::Node Parser::filename_to_node(std::string filename)
136  {
137  YAML::Node root;
138  // Read inifile file
139  try
140  {
141  root = YAML::LoadFile(filename);
142  }
143  catch (YAML::Exception &e)
144  {
145  std::ostringstream msg;
146  msg << "Error reading Inifile \""<<filename<<"\"! ";
147  msg << "Please check that file exist!" << endl;
148  msg << "(yaml-cpp error: "<<e.what()<<" )";
149  inifile_error().raise(LOCAL_INFO,msg.str());
150  }
151  return root;
152  }
153 
154  void Parser::basicParse(YAML::Node root, std::string filename)
155  {
156  recursiveImport(root,filename);
157  parametersNode = root["Parameters"];
158  priorsNode = root["Priors"];
159  printerNode = root["Printer"];
160  scannerNode = root["Scanner"];
161  logNode = root["Logger"];
162  keyValuePairNode = root["KeyValues"];
163 
164  // Set default output path
165  std::string defpath;
166  if(hasKey("default_output_path"))
167  {
168  defpath = getValue<std::string>("default_output_path");
169  }
170  else
171  {
172  // Assign a default default (;)) path based on the yaml file name
173  // Ridiculously we have to parse manually in C++ since no
174  // standard library tools for doing this exist...
175  // Assumes that file extension has only one dot, or that
176  // there is no file extension. Should work anyway if more
177  // dots, will just get a directory name with a dot in it.
178  size_t fname_start = filename.find_last_of("/\\");
179  size_t fname_end = filename.find_last_of(".");
180  str fname = filename.substr(fname_start+1,fname_end);
181  defpath = "runs/" + fname + "/";
182  }
183  scannerNode["default_output_path"] = Utils::ensure_path_exists(defpath+"/scanner_plugins/");
184  logNode ["default_output_path"] = Utils::ensure_path_exists(defpath+"/logs/");
185  printerNode["options"]["default_output_path"] = Utils::ensure_path_exists(defpath+"/samples/");
186 
187  // Postprocessor is currently incompatible with 'print_timing_data', so need to pass this option on for checking
188  scannerNode["print_timing_data"] = getValueOrDef<bool>(false,"print_timing_data");
189 
190  // Pass on minimum recognised lnlike and offset to Scanner
191  scannerNode["model_invalid_for_lnlike_below"] = getValueOrDef<double>(0.9*std::numeric_limits<double>::lowest(), "likelihood", "model_invalid_for_lnlike_below");
192  if (hasKey("likelihood", "lnlike_offset"))
193  scannerNode["lnlike_offset"] = getValue<double>("likelihood", "lnlike_offset");
194 
195  // Set fatality of exceptions
196  if (hasKey("exceptions"))
197  {
198  // Iterate over the map of all recognised exception objects
199  std::map<const char*,exception*>::const_iterator iter;
200  for (iter = exception::all_exceptions().begin(); iter != exception::all_exceptions().end(); ++iter)
201  {
202  // Check if the exception has an entry in the YAML file
203  if (hasKey("exceptions",iter->first))
204  {
205  // Retrieve the entry and set the exception's 'fatal' flag accordingly.
206  str value = getValue<str>("exceptions",iter->first);
207  if (value == "fatal")
208  {
209  iter->second->set_fatal(true);
210  }
211  else if (value == "non-fatal")
212  {
213  iter->second->set_fatal(false);
214  }
215  else
216  {
217  str error_msg = "Unrecognised entry \"" + value + "\" for exceptions key \"" + iter->first + "\" in input file.";
218  inifile_error().raise(LOCAL_INFO,error_msg);
219  }
220  }
221  }
222  }
223 
224  // Parse the logging setup node, and initialise the LogMaster object
225  std::string prefix;
226  if(logNode["prefix"])
227  {
228  prefix = logNode["prefix"].as<std::string>();
229  }
230  else
231  {
232  prefix = logNode["default_output_path"].as<std::string>()+"/";
233  }
234 
235  // map storing info used to set up logger objects
236  std::map<std::set<std::string>,std::string> loggerinfo;
237  if(logNode["redirection"])
238  {
239  YAML::Node redir = logNode["redirection"];
240  for(YAML::const_iterator it=redir.begin(); it!=redir.end(); ++it)
241  {
242  std::set<std::string> tags;
243  std::string filename;
244  // Iterate through tags and add them to the set
245  YAML::Node yamltags = it->first;
246  for(YAML::const_iterator it2=yamltags.begin();it2!=yamltags.end();++it2)
247  {
248  tags.insert( it2->as<std::string>() );
249  }
250  filename = (it->second).as<std::string>();
251 
252  // Add entry to the loggerinfo map
253  if((filename=="stdout") or (filename=="stderr"))
254  {
255  // Special cases to trigger redirection to standard output streams
256  loggerinfo[tags] = filename;
257  }
258  else
259  {
260  // The logger won't be able to create the log files if the prefix
261  // directory doesn't exist, so let us now make sure that it does
262  loggerinfo[tags] = Utils::ensure_path_exists(prefix + filename);
263  }
264  }
265  }
266  else
267  {
268  // Use default log file only
269  std::set<std::string> tags;
270  std::string filename;
271  tags.insert("Default");
272  filename = "default.log";
273  loggerinfo[tags] = Utils::ensure_path_exists(prefix + filename);
274  }
275  // Initialise global LogMaster object
276  bool master_debug = (keyValuePairNode["debug"]) ? keyValuePairNode["debug"].as<bool>() : false;
277  bool logger_debug = (logNode["debug"]) ? logNode["debug"].as<bool>() : false;
278  logger().set_log_debug_messages(master_debug or logger_debug);
279  logger().initialise(loggerinfo);
280 
281  // Parse the Parameters node and expand out some shorthand syntax
282  // e.g.
283  // model1
284  // param1: 5.678
285  // expands to
286  // model1
287  // param1:
288  // fixed_value: 5.678
289  // Parameter must have no entries besides the value for this syntax to be valid
290  }
291 
294  YAML::Node Parser::getParametersNode() const {return parametersNode;}
295  YAML::Node Parser::getPriorsNode() const {return priorsNode;}
296  YAML::Node Parser::getPrinterNode() const {return printerNode;}
297  YAML::Node Parser::getScannerNode() const {return scannerNode;}
298  YAML::Node Parser::getLoggerNode() const {return logNode;}
299  YAML::Node Parser::getKeyValuePairNode() const {return keyValuePairNode;}
301 
304  bool Parser::hasModelParameterEntry(std::string model, std::string param, std::string key) const
305  {
306  return parametersNode[model][param][key];
307  }
308 
310  const std::set<str> Parser::getModelNames() const
311  {
312  std::set<str> result;
313  for (YAML::const_iterator it = parametersNode.begin(); it!=parametersNode.end(); ++it)
314  {
315  if (it->first.as<std::string>() != "adhoc")
316  result.insert( it->first.as<std::string>() );
317  }
318  return result;
319  }
320 
321  const std::vector<std::string> Parser::getModelParameters(std::string model) const
322  {
323  std::vector<std::string> result;
324  if (parametersNode[model])
325  {
326  for (YAML::const_iterator it = parametersNode[model].begin(); it!=parametersNode[model].end(); ++it)
327  {
328  result.push_back( it->first.as<std::string>() );
329  }
330  }
331  return result;
332  }
333 
335  const Options Parser::getOptions(std::string key) const
336  {
337  if (hasKey(key, "options"))
338  {
339  return Options(keyValuePairNode[key]["options"]);
340  }
341  else
342  {
343  return Options(keyValuePairNode[key]);
344  }
345  }
346 
348 
349 
350  }
351 }
EXPORT_SYMBOLS str dir_name(const str &path)
Get directory name from full path+filename (POSIX)
void recursiveImport(const YAML::Node &node, const std::string &filename)
Header for logging classes.
#define LOCAL_INFO
Definition: local_info.hpp:34
Base class for ini-file parsers using yaml-cpp.
YAML::Node filename_to_node(str)
Read in the actual YAML file.
Logging access header for GAMBIT.
General small utility functions.
const std::vector< str > getModelParameters(str model) const
const Options getOptions(str key) const
Getter for options.
YAML::Node getPriorsNode() const
bool hasKey(args... keys) const
int importRound(YAML::Node node, const std::string &filename)
Recursive import.
YAML::Node getPrinterNode() const
void set_log_debug_messages(bool flag)
Choose whether "Debug" tagged log messages will be ignored (i.e. not logged)
Definition: logmaster.hpp:138
Logging::LogMaster & logger()
Function to retrieve a reference to the Gambit global log object.
Definition: logger.cpp:95
std::string str
Shorthand for a standard string.
Definition: Analysis.hpp:35
EXPORT_SYMBOLS const str & ensure_path_exists(const str &)
Ensure that a path exists (and then return the path, for chaining purposes)
void initialise(std::vector< std::pair< std::set< std::string >, std::string >> &)
Function to construct loggers according to blueprint.
Definition: logmaster.cpp:223
virtual void readFile(str filename)
Read in the YAML file.
bool hasModelParameterEntry(str model, str param, str key) const
Getters for model/parameter section.
A simple C++ wrapper for the MPI C bindings.
YAML::Node getScannerNode() const
const std::set< str > getModelNames() const
Return list of model names (without "adhoc" model!)
error & inifile_error()
IniFile errors.
YAML::Node getLoggerNode() const
YAML::Node getParametersNode() const
Getters for key/value section.
void basicParse(YAML::Node, str)
Do the basic parsing of the YAML file.
TODO: see if we can use this one:
Definition: Analysis.hpp:33
A small wrapper object for &#39;options&#39; nodes.
YAML::Node getKeyValuePairNode() const