MaCh3  2.6.1
Reference Guide
InputManager.cpp
Go to the documentation of this file.
1 #include "InputManager.h"
2 
3 namespace M3 {
4 namespace Plotting {
5 // this is the constructor with user specified translation config file
6 InputManager::InputManager(const std::string &translationConfigName, const std::vector<std::string>& _fileNames) {
7  // read the config file
8  _translatorConfig = M3OpenConfig(translationConfigName);
9 
10  MACH3LOG_DEBUG("InputManager: have loaded translation config file");
11 
12  // split up the parts of the config for easier access later
13  _fitterSpecConfig = _translatorConfig["FitterSpec"];
14  _parametersConfig = _translatorConfig["Parameters"];
15  _samplesConfig = _translatorConfig["Samples"];
16 
17  // check the config file and get which parameters, samples, and fitters we've been told about
18  _knownFitters = Get<std::vector<std::string>>(_fitterSpecConfig["fitters"], __FILE__, __LINE__);
19  _knownParameters = Get<std::vector<std::string>>(_parametersConfig["Parameters"], __FILE__, __LINE__);
20  _knownSamples = Get<std::vector<std::string>>(_samplesConfig["Samples"], __FILE__, __LINE__);
21 
22  if(_knownParameters.size() == 0){
24  }
25  MACH3LOG_DEBUG("Will now check the specified parameters for tags");
26 
27  // loop through all parameters and get their tags
28  for ( const std::string &param: _knownParameters )
29  {
30  std::vector<std::string> tags;
31 
32  MACH3LOG_DEBUG("Looking for tags for parameter {}", param);
33  if ( _parametersConfig[param] )
34  {
35  if ( _parametersConfig[param]["tags"] )
36  {
37  tags = Get<std::vector<std::string>>(_parametersConfig[param]["tags"], __FILE__, __LINE__);
38  MACH3LOG_DEBUG(" - Found {}!", tags.size());
39  }
40  }
41  _paramToTagsMap[param] = tags;
42  }
43 
44  MACH3LOG_DEBUG("Will now check the specified samples for tags");
45 
46  // same again for samples
47  for ( const std::string &samp: _knownSamples )
48  {
49  std::vector<std::string> tags;
50 
51  MACH3LOG_DEBUG("Looking for tags for sample {}", samp);
52  if ( _samplesConfig[samp])
53  {
54  if ( _samplesConfig[samp]["tags"] )
55  {
56  tags = Get<std::vector<std::string>>(_samplesConfig[samp]["tags"], __FILE__, __LINE__);
57  MACH3LOG_DEBUG(" - Found {}!", tags.size());
58  }
59  }
60  _sampleToTagsMap[samp] = tags;
61  }
62 
63  for (std::string fileName : _fileNames) {
64  addFile(fileName);
65  }
66 }
67 
76 void InputManager::addFile(const std::string &fileName) {
77  _fileVec.emplace_back(fileName);
78 
79  // EM: need to be done in this order since fillFileData needs to know info about the file, e.g.
80  // fitter and what things are in it
81  InputFile &fileInfo = _fileVec.back();
82  fillFileInfo(fileInfo);
83  fillFileData(fileInfo);
84 }
85 
89 void InputManager::print(const std::string &printLevel) const {
90  MACH3LOG_INFO("Printing contents of InputManager instance:");
91 
92  if (printLevel == "dump")
93  {
94  MACH3LOG_INFO("parameters known to this manager: ");
95  for (std::string param : _knownParameters)
96  {
97  MACH3LOG_INFO(" ");
98  }
99  }
100 
101  int fileCount = 0;
102  for (const InputFile &file : _fileVec)
103  {
104  MACH3LOG_INFO(" For file {}", fileCount);
105  if (printLevel == "summary")
106  {
107  file.Summarise();
108  } else if (printLevel == "dump")
109  { file.Dump(); }
110  fileCount++;
111  }
112 
113  MACH3LOG_INFO("");
114 }
115 
116 double InputManager::getPostFitError(const int fileNum, const std::string &paramName,
117  std::string errorType) const {
118  const InputFile &inputFileDef = getFile(fileNum);
119 
120  // set default type if not specified
121  if (errorType == "")
122  errorType = inputFileDef.defaultErrorType;
123 
124  if (inputFileDef.postFitErrors.find(errorType) == inputFileDef.postFitErrors.end())
125  {
126  MACH3LOG_CRITICAL("Requested error type, {} does not exist in the specified file: ", errorType);
127  MACH3LOG_CRITICAL(" {}", inputFileDef.fileName);
128  MACH3LOG_CRITICAL(" at index {}", fileNum);
129 
130  throw MaCh3Exception(__FILE__ , __LINE__ );
131  }
132 
133  if (inputFileDef.postFitErrors.at(errorType).find(paramName) !=
134  inputFileDef.postFitErrors.at(errorType).end())
135  {
136  return inputFileDef.postFitErrors.at(errorType).at(paramName);
137  }
138 
139  MACH3LOG_WARN("Didn't find {} post fit error for {}. Returning {}", errorType, paramName, M3::_BAD_DOUBLE_);
140 
141  return M3::_BAD_DOUBLE_;
142 }
143 
144 double InputManager::getPostFitValue(const int fileNum, const std::string &paramName,
145  std::string errorType) const {
146  const InputFile &inputFileDef = getFile(fileNum);
147 
148  // set default type if not specified
149  if (errorType == "")
150  errorType = inputFileDef.defaultErrorType;
151 
152  if (inputFileDef.postFitErrors.find(errorType) == inputFileDef.postFitErrors.end())
153  {
154  MACH3LOG_CRITICAL("Requested error type, {} does not exist in the specified file: ", errorType);
155  MACH3LOG_CRITICAL(" {}", inputFileDef.fileName);
156  MACH3LOG_CRITICAL(" at index {}", fileNum);
157 
158  throw MaCh3Exception(__FILE__ , __LINE__ );
159  }
160 
161  if (inputFileDef.postFitValues.at(errorType).find(paramName) !=
162  inputFileDef.postFitValues.at(errorType).end())
163  {
164  return inputFileDef.postFitValues.at(errorType).at(paramName);
165  }
166 
167  MACH3LOG_WARN("Didn't find {} post fit value for {}. Returning {}", errorType, paramName, M3::_BAD_DOUBLE_);
168 
169  return M3::_BAD_DOUBLE_;
170 }
171 
172 
173 // ##################################################################
174 // ################## End of public interface #######################
175 // ##################################################################
176 
177 std::vector<std::string> InputManager::getTaggedValues(const std::vector<std::string> &values,
178  const std::unordered_map<std::string, std::vector<std::string>> &tagMap,
179  const std::vector<std::string> &tags, std::string checkType) const {
180  // check that checkType is valid
181  if(
182  checkType != "all" &&
183  checkType != "any" &&
184  checkType != "exact"
185  )
186  {
187  MACH3LOG_ERROR("Invalid tag check type specified: {}. Will instead use the default type: 'all'", checkType);
188  checkType = "all";
189  }
190 
191  // If no tags were specified, take this to mean that anything should be a match
192  if (tags.size() == 0) return values;
193 
194  std::vector<std::string> retVec;
195 
196  MACH3LOG_DEBUG("Getting tagged values using checkType {}", checkType);
197  for ( std::string val: values )
198  {
199  MACH3LOG_DEBUG("Checking tags of {}", val);
200  // get the tags that this value has
201  const std::vector<std::string> &valTags = tagMap.at(val);
202 
203  // we can skip it if it has no tags
204  if (valTags.size() == 0) continue;
205 
206  // count how many of the specified tags match the tags of the current value
207  unsigned int tagCount = 0;
208  for ( const std::string &tag: tags )
209  {
210  if ( std::find( valTags.begin(), valTags.end(), tag ) != valTags.end() )
211  {
212  MACH3LOG_DEBUG(" - Matched tag {} !", tag);
213  tagCount ++;
214  }
215  }
216 
217  // now decide if we include the current value based on the check type
218  if ( checkType == "all" )
219  {
220  if ( tagCount == tags.size() ) retVec.push_back(val);
221  }
222  else if ( checkType == "any" )
223  {
224  if ( tagCount > 0 ) retVec.push_back(val);
225  }
226  else if ( checkType == "exact" )
227  {
228  // EM: note that this will break if duplicate tags are specified in either vector... so please don't do that
229  if ( tagCount == valTags.size() ) retVec.push_back(val);
230  }
231  }
232  MACH3LOG_DEBUG("Found {} values matching the specified tags", retVec.size());
233  return retVec;
234 }
235 
236 std::vector<std::string> InputManager::parseLocation(const std::string &rawLocationString, std::string &fitter,
237  fileTypeEnum fileType, const std::string &parameter,
238  const std::string &sample, const std::string &parameter2) const {
239  std::string locationString(rawLocationString);
240  std::vector<std::string> tokens;
241 
242  std::size_t pos = 0;
243  std::string toReplace = "";
244 
245  // loop through the raw location string and replace any instance of {PARAMETER} with the name of
246  // the parameter
247  toReplace = "{PARAMETER}";
248  while ((pos = locationString.find(toReplace)) != std::string::npos)
249  {
250  locationString.replace(pos, toReplace.length(),
251  getFitterSpecificParamName(fitter, fileType, parameter));
252  }
253 
254  // same again with {SAMPLE}
255  toReplace = "{SAMPLE}";
256  while ((pos = locationString.find(toReplace)) != std::string::npos)
257  {
258  locationString.replace(pos, toReplace.length(),
259  getFitterSpecificSampleName(fitter, fileType, sample));
260  }
261 
262  // loop through the raw location string and replace any instance of {PARAMETER2} with the name of
263  // the second specified parameter
264  toReplace = "{PARAMETER2}";
265  while ((pos = locationString.find(toReplace)) != std::string::npos)
266  {
267  locationString.replace(pos, toReplace.length(),
268  getFitterSpecificParamName(fitter, fileType, parameter2));
269  }
270 
271  // Now we go through and look for ":" and split the location into two parts
272  // first part should be the directory to look for the parameter
273  // lats part should be the end of the name of the object to look for
274  std::string token;
275  std::string delimiter = ":";
276  while ((pos = locationString.find(delimiter)) != std::string::npos)
277  {
278  token = locationString.substr(0, pos);
279  tokens.push_back(token);
280  locationString.erase(0, pos + delimiter.length());
281  }
282  tokens.push_back(locationString);
283 
284  // should only have found 2 parts, anything more means there was too many
285  // ":" in the location string
286  if (tokens.size() > 2)
287  {
288  throw MaCh3Exception(__FILE__ , __LINE__, "Too many : tokens in location string: " + rawLocationString);
289  }
290 
291  return tokens;
292 }
293 
294 std::shared_ptr<TObject> InputManager::findRootObject(const InputFile &fileDef,
295  const std::vector<std::string> &locationVec) const {
296  std::shared_ptr<TObject> object = nullptr;
297 
298  // if vector only has one element, just interpret it as the absolute path to the object
299  if (locationVec.size() == 1)
300  {
301  object = std::shared_ptr<TObject>(fileDef.file->Get(locationVec[0].c_str()));
302  }
303 
304  // if vector has two elements, interpret the first as the directory and the second as a string to
305  // match with the end of the objects in the file
306  else if (locationVec.size() == 2)
307  {
308  TDirectoryFile *directory = fileDef.file->Get<TDirectoryFile>(locationVec[0].c_str());
309  size_t nMatchingObjects = 0;
310 
311  // let's make sure that the directory itself exists
312  if (directory == nullptr)
313  {
314  object = nullptr;
315  }
316  else
317  {
318  // loop through the keys in the directory and find objects whose name matches the specified
319  // pattern
320  TIter next(directory->GetListOfKeys());
321  while (TKey *key = static_cast<TKey*>(next()))
322  {
323  if (strEndsWith(std::string(key->GetName()), locationVec[1]))
324  {
325  object = std::shared_ptr<TObject>(directory->Get(key->GetName()));
326  nMatchingObjects++;
327  }
328  }
329  }
330  // check that only one object matched the pattern
331  if (nMatchingObjects > 1)
332  {
333  MACH3LOG_CRITICAL("Too many objects match the pattern specified by {} {}", locationVec[0], locationVec.size()==2 ? locationVec[1] : "");
334  MACH3LOG_CRITICAL("Found {} matching objects, should just be one", nMatchingObjects);
335 
336  throw MaCh3Exception(__FILE__ , __LINE__ );
337  }
338  }
339  else // Vector too big!!
340  {
341  MACH3LOG_CRITICAL("Invalid object location vector");
342  MACH3LOG_CRITICAL("Should have two elements: [ (directory to look in), (end of the name of the object) ]");
343  MACH3LOG_CRITICAL("Or one element that is just the absolute path to the object");
344 
345  throw MaCh3Exception(__FILE__ , __LINE__ );
346  }
347  return object;
348 }
349 
350 bool InputManager::findBySampleLLH(InputFile &inputFileDef, const std::string &parameter,
351  std::string &fitter, const std::string &sample, bool setInputFileScan) {
352  YAML::Node thisFitterSpec_config = _fitterSpecConfig[fitter];
353 
354  // EM: Get where the by sample LLH scan for this parameter *should* live if it exists
355  YAML::Node testLLHConfig = thisFitterSpec_config["bySample_LLH"];
356  auto testLLHRawLocations = Get<std::vector<std::string>>(testLLHConfig["location"], __FILE__, __LINE__);
357 
358  auto LLHObjType = Get<std::string>(thisFitterSpec_config["LLHObjectType"], __FILE__, __LINE__);
359  // EM: Now look for the parameter in this folder
360  std::shared_ptr<TObject> LLHObj = nullptr;
361  for (std::string rawLocation : testLLHRawLocations)
362  {
363  LLHObj =
364  findRootObject(inputFileDef, parseLocation(rawLocation, fitter, kLLH, parameter, sample));
365  if (LLHObj != nullptr)
366  {
367  break;
368  }
369  }
370 
371  // EM: If it's not in there we can return here
372  if (LLHObj == nullptr)
373  return false;
374 
375  // EM: If specified, we set the object in the InputFile object
376  if (setInputFileScan)
377  {
378  std::shared_ptr<TGraph> LLHGraph = std::make_shared<TGraph>();
379 
380  if (LLHObjType == "TH1D")
381  {
382  LLHGraph = std::make_shared<TGraph>(static_cast<TH1D*>(LLHObj.get()));
383  } else if (LLHObjType == "TGraph")
384  {
385  LLHGraph = std::shared_ptr<TGraph>(static_cast<TGraph*>(LLHObj->Clone()));
386  } else
387  {
388  throw MaCh3Exception(__FILE__ , __LINE__, "uknown type of LLH object specified: " + LLHObjType);
389  }
390 
391  inputFileDef.LLHScansBySample_map[sample][parameter] = LLHGraph;
392  }
393  return true;
394 }
395 
396 // check the input file for raw MCMC step values for a particular parameter
397 bool InputManager::findRawChainSteps(InputFile &inputFileDef, const std::string &parameter, std::string &fitter, bool setInputBranch) const {
398  // we'll assume for now that the chain is in the form of a TTree and the branch names are parameter names
399  bool wasFound = false;
400 
401  // make sure that the filedef object has all the necessary stuff to read from the posterior tree
402  if ( (inputFileDef.mcmcProc != nullptr) && (inputFileDef.posteriorTree != nullptr) )
403  {
404  const std::vector<TString> branchNames = inputFileDef.mcmcProc->GetBranchNames();
405 
406  std::string specificName = getFitterSpecificParamName(fitter, kMCMC, parameter);
407 
408  // loop over possible parameters and compare names
409  for ( int paramIdx = 0; paramIdx < inputFileDef.mcmcProc->GetNParams() -1 ; paramIdx ++ )
410  {
411  TString title;
412  double prior, priorError; // <- will be discarded
413  inputFileDef.mcmcProc->GetNthParameter(paramIdx, prior, priorError, title);
414 
415  // KS: Fitter Base output used for LLH only may be ill-configured
416  if (!inputFileDef.posteriorTree->GetBranch(branchNames[paramIdx])) {
417  MACH3LOG_DEBUG("Branch {} not found in chain, skipping!", branchNames[paramIdx]);
418  continue;
419  }
420 
421  if ( strEndsWith(title.Data(), specificName) )
422  {
423  wasFound = true;
424  if ( setInputBranch )
425  {
426  // EM: should probably use MCMCProcessor for this so we can use caching, gpu etc.
427  inputFileDef.MCMCstepParamsMap[parameter] = new double( M3::_BAD_DOUBLE_ ); // <- initialise the parameter step values
428  inputFileDef.posteriorTree->SetBranchAddress( branchNames[paramIdx], inputFileDef.MCMCstepParamsMap.at(parameter) );
429  }
430  break;
431  }
432  }
433  }
434  return wasFound;
435 }
436 
437 // check the input file for processed 1d posteriors for a particular parameter
438 bool InputManager::find1dPosterior(InputFile &inputFileDef, const std::string &parameter, std::string &fitter, bool setFileData) const {
439  bool wasFound = false;
440 
441  YAML::Node thisFitterSpec_config = _fitterSpecConfig[fitter];
442 
443  if ( thisFitterSpec_config["1dPosteriors"] ) {
444  auto rawLocations = Get<std::vector<std::string>>(thisFitterSpec_config["1dPosteriors"]["location"],
445  __FILE__, __LINE__);
446  for ( const std::string &rawLoc : rawLocations)
447  {
448  std::shared_ptr<TH1D> posterior1d = std::static_pointer_cast<TH1D>(findRootObject(inputFileDef, parseLocation(rawLoc, fitter, kMCMC, parameter)));
449 
450  if ( posterior1d != nullptr )
451  {
452  wasFound = true;
453 
454  if ( setFileData )
455  {
456  inputFileDef.posteriors1d_map[parameter] = std::make_shared<TGraph>(posterior1d.get());
457  }
458  break;
459  }
460  }
461  }
462  return wasFound;
463 }
464 
465 bool InputManager::findPostFitParamError(InputFile &inputFileDef, const std::string &parameter,
466  std::string &fitter, const std::string &errorType,
467  const bool setInputFileError) {
468  std::string specificName = getFitterSpecificParamName(fitter, kPostFit, parameter);
469  YAML::Node thisFitterSpec_config = _fitterSpecConfig[fitter];
470 
471  // EM: Get which hist this parameter lives in from the config
472  YAML::Node postFitErrorTypes = thisFitterSpec_config["postFitErrorTypes"];
473  YAML::Node specificErrorType = postFitErrorTypes[errorType];
474  auto postFitLocations = Get<std::vector<std::string>>(specificErrorType["location"], __FILE__, __LINE__);
475 
476  // EM: If the parameter has a specified list of locations then override the default one
477  std::vector<std::string> postFitLocations_override;
478  if (getFitterSpecificParamOption<std::vector<std::string>>(fitter, "postFitLoc",
479  postFitLocations_override, parameter))
480  {
481  postFitLocations = postFitLocations_override;
482  }
483 
484  for (std::string postFitLoc : postFitLocations)
485  {
486  std::shared_ptr<TH1D> postFitErrors = std::static_pointer_cast<TH1D>(findRootObject(inputFileDef, parseLocation(postFitLoc, fitter, kPostFit, parameter)));
487 
488  // EM: the postfit hist for this parameter isn't in this file
489  if (postFitErrors == nullptr)
490  continue;
491 
492  // EM: Loop through the hist to see if it contains the parameter we're looking for
493  for (int binIdx = 0; binIdx <= postFitErrors->GetNbinsX(); binIdx++)
494  {
495  std::string binLabel = std::string(postFitErrors->GetXaxis()->GetBinLabel(binIdx));
496  if (strEndsWith(binLabel, specificName))
497  {
498  if (setInputFileError)
499  {
500  // EM: if specified, we fill the postfit error TH1D in the provided InputFile object
501  inputFileDef.postFitErrors[errorType][parameter] = postFitErrors->GetBinError(binIdx);
502  inputFileDef.postFitValues[errorType][parameter] = postFitErrors->GetBinContent(binIdx);
503  }
504 
505  return true;
506  }
507  }
508  }
509  // EM: Didn't find the parameter in any of the specified locations
510  return false;
511 }
512 
513 // EM: Lots of room for improvement in fillFileInfo and fillFileData, should be split up into more
514 // methods, currently a lot of copy pasting
515 void InputManager::fillFileInfo(InputFile &inputFileDef, const bool printThoughts) {
520 
521  // use the contents of the file to decide which fitter it came from and what type of file it is
522  if (printThoughts)
523  MACH3LOG_INFO("Checking contents of file {}", inputFileDef.fileName);
524 
525  for (std::string fitter: _knownFitters)
526  {
527  // flag for whether or not the current fitter is the correct one
528  bool foundFitter = false;
529  if (printThoughts)
530  MACH3LOG_INFO("Checking if this is a {} file", fitter);
531 
532  // EM: get the configuration specifying what the output of this fitter looks like
533  if (!_fitterSpecConfig[fitter])
534  {
535  throw MaCh3Exception(__FILE__ , __LINE__, "translation config doesnt contain a definition for fitter " + fitter);
536  }
537 
538  YAML::Node thisFitterSpec_config = _fitterSpecConfig[fitter];
539 
540  size_t numLLHParams;
541 
542  // ##### Look for LLH scans in the input #####
543  // check for all 3 LLH directory types
544  for (std::string LLHType : {"sample", "penalty", "total"})
545  {
546  if (printThoughts)
547  MACH3LOG_INFO(".... searching for {} LLH scans... ", LLHType);
548 
549  // vector of all the possible locations that we might find LLH scans for this type of LLH
550  YAML::Node testLLHConfig = thisFitterSpec_config[LLHType + "_LLH"];
551  auto testLLHRawLocations = Get<std::vector<std::string>>(testLLHConfig["location"], __FILE__, __LINE__);
552 
553  // counter for the total number of parameters we find scans for
554  numLLHParams = 0;
555 
556  std::vector<std::string> enabledLLHParams;
557 
558  for (const std::string &parameter : _knownParameters)
559  {
560  MACH3LOG_DEBUG(" - for {}", parameter);
561  inputFileDef.availableParams_map_LLH[LLHType][parameter] = false;
562 
563  // check if we find the parameter at any of the locations we think it should be at
564  for (const std::string &rawLocation : testLLHRawLocations)
565  {
566  if (findRootObject(inputFileDef, parseLocation(rawLocation, fitter, kLLH, parameter)) !=
567  nullptr)
568  {
569  numLLHParams++;
570  enabledLLHParams.push_back(parameter);
571  inputFileDef.availableParams_map_LLH[LLHType][parameter] = true;
572  MACH3LOG_DEBUG(" FOUND!");
573  break; // <- we've found it, no point checking the rest of the locations
574  }
575  }
576  }
577 
578  if (printThoughts)
579  MACH3LOG_INFO(".... Found {}", numLLHParams);
580 
581  if (numLLHParams > 0)
582  {
583  foundFitter = true;
584  inputFileDef.hasLLHScans = true;
585  inputFileDef.availableParams_LLH = enabledLLHParams;
586  inputFileDef.hasLLHScans_map[LLHType] = true;
587  }
588 
591  }
592 
593  if (printThoughts)
594  MACH3LOG_INFO("");
595 
596  // ##### now look for processed post fit errors #####
597  if (printThoughts)
598  {
599  MACH3LOG_INFO("....searching for Post Fit Parameters");
600 
601  if (thisFitterSpec_config["defaultPostFitErrorType"])
602  {
603  MACH3LOG_DEBUG(" Default type specified with possible locations: ");
604  YAML::Node postFitErrorSpec = thisFitterSpec_config["postFitErrorTypes"];
605  YAML::Node defaultErrorType =
606  postFitErrorSpec[thisFitterSpec_config["defaultPostFitErrorType"].as<std::string>()];
607  auto locations = Get<std::vector<std::string>>(defaultErrorType["location"], __FILE__, __LINE__);
608  for (std::string loc : locations)
609  MACH3LOG_DEBUG(loc);
610  }
611  else
612  {
613  MACH3LOG_DEBUG(" No default location specified");
614  }
615  }
616 
617  int numPostFitParams = 0;
618  std::vector<std::string> enabledPostFitParams;
619 
620  auto defaultErrorType =
621  Get<std::string>(thisFitterSpec_config["defaultPostFitErrorType"], __FILE__, __LINE__);
622  for (std::string parameter : _knownParameters)
623  {
624  if (findPostFitParamError(inputFileDef, parameter, fitter, defaultErrorType))
625  {
626  numPostFitParams++;
627  enabledPostFitParams.push_back(parameter);
628  }
629  }
630 
631  if (printThoughts)
632  MACH3LOG_INFO(".... Found {}", numPostFitParams);
633 
634  if (numPostFitParams > 0)
635  {
636  foundFitter = true;
637  inputFileDef.hasPostFitErrors = true;
638  inputFileDef.availableParams_postFitErrors = enabledPostFitParams;
639  }
640 
641  // ######### Now look for LLH scans broken down by sample #########
642  // This is really just a check to see if the number of by sample LLH scans is the same as normal
643  // LLH scans
644  if (printThoughts)
645  MACH3LOG_INFO("....Searching for LLH scans broken down by sample");
646 
647  for (const std::string &sample : _knownSamples)
648  {
649  size_t numLLHBySampleParams = 0;
650  for (const std::string &parameter : _knownParameters)
651  {
652  inputFileDef.availableParams_map_LLHBySample[sample][parameter] = false;
653  if (findBySampleLLH(inputFileDef, parameter, fitter, sample))
654  {
655  inputFileDef.availableParams_map_LLHBySample[sample][parameter] = true;
656  numLLHBySampleParams++;
657  }
658  }
659 
660  if (numLLHBySampleParams != 0)
661  {
662  inputFileDef.availableSamples_LLH.push_back(sample);
663 
664  if (printThoughts)
665  MACH3LOG_INFO("........ Found {} LLH scans for sample {}", numLLHBySampleParams, sample);
666 
667  if ((numLLHParams != numLLHBySampleParams))
668  {
669  MACH3LOG_ERROR("hmmmmm something weird is happening here");
670  MACH3LOG_ERROR(" I have {} LLH scans for sample {}", numLLHBySampleParams, sample);
671  MACH3LOG_ERROR(" But {} parameters with Total_LLH scals", numLLHParams);
672  }
673  }
674  }
675 
676  // ######### Now for the main event: Look for MCMC chains and processed posteriors ###########
677 
678  // EM: if "MCMCsteps" was defined for this fitter, we assume that it is a MaCh3 raw MCMC file
679  // thus it needs an MCMCProcessor to read from it. This isn't super general and it would probably
680  // be good to have some additional "isMaCh3" option that can decide whether or not to use MCMCProcessor
681  // but hey ho it's good enough for now
682  if ( thisFitterSpec_config["MCMCsteps"] )
683  {
684  MACH3LOG_DEBUG("Initialising MCMCProcessor for the input file");
685  auto posteriorTreeRawLocations =
686  Get<std::vector<std::string>>(thisFitterSpec_config["MCMCsteps"]["location"], __FILE__, __LINE__);
687 
688  TTree *postTree = nullptr;
689  for ( const std::string &rawLoc: posteriorTreeRawLocations )
690  {
691  MACH3LOG_DEBUG(" - Looking for MCMC chain parameter values at: {}", rawLoc);
692 
693  postTree = inputFileDef.file->Get<TTree>(rawLoc.c_str());
694 
695  if ( postTree != nullptr && (postTree->GetNbranches() != 0) )
696  {
697  inputFileDef.mcmcProc = std::make_unique<MCMCProcessor>(inputFileDef.fileName);
698  // KS: We need this so plotting doesn't overwrite default...
699  inputFileDef.mcmcProc->SetOutputSuffix("_PlottingTemp");
700  inputFileDef.mcmcProc->Initialise();
701 
702  MACH3LOG_DEBUG(" - FOUND!");
703  break;
704  }
705  }
706 
707  if ( postTree != nullptr && (postTree->GetNbranches() != 0) )
708  {
709  inputFileDef.posteriorTree = postTree;
710  inputFileDef.nMCMCentries = int(postTree->GetEntries());
711  }
712  }
713 
714  if (printThoughts)
715  {
716  MACH3LOG_INFO("....Searching for MCMC related things");
717  }
718 
719  size_t num1dPosteriors = 0;
720  std::vector<std::string> enabled1dPosteriorParams;
721 
722  size_t numMCMCchainParams = 0;
723  std::vector<std::string> enabledMCMCchainParams;
724 
725  for ( const std::string &parameter : _knownParameters )
726  {
727  MACH3LOG_DEBUG(" - for {}", parameter);
728  // check for 1d post processing posterior.q
729  inputFileDef.availableParams_map_1dPosteriors[parameter] = false;
730  if ( thisFitterSpec_config["1dPosteriors"] && find1dPosterior(inputFileDef, parameter, fitter) )
731  {
732  MACH3LOG_DEBUG(" Found 1d processed posterior!");
733  enabled1dPosteriorParams.push_back(parameter);
734  num1dPosteriors++;
735  inputFileDef.availableParams_map_1dPosteriors[parameter] = true;
736  }
737  // now check for parameters in chain
738  inputFileDef.availableParams_map_MCMCchain[parameter] = false;
739  if ( thisFitterSpec_config["MCMCsteps"] && findRawChainSteps(inputFileDef, parameter, fitter) )
740  {
741  MACH3LOG_DEBUG(" Found raw MCMC steps!");
742  enabledMCMCchainParams.push_back(parameter);
743  numMCMCchainParams++;
744  inputFileDef.availableParams_map_MCMCchain[parameter] = true;
745  }
746  }
747 
748  if (num1dPosteriors > 0 )
749  {
750  foundFitter = true;
751  inputFileDef.has1dPosteriors = true;
752  inputFileDef.availableParams_1dPosteriors = enabled1dPosteriorParams;
753 
754  if (printThoughts)
755  MACH3LOG_INFO("........ Found {} 1d processed posteriors", num1dPosteriors);
756  }
757  if ( numMCMCchainParams > 0 )
758  {
759  foundFitter = true;
760  inputFileDef.hasMCMCchain = true;
761  inputFileDef.availableParams_MCMCchain = enabledMCMCchainParams;
762 
763  if (printThoughts)
764  MACH3LOG_INFO("........ Found {} parameters in MCMC chain", numMCMCchainParams);
765  }
766 
767  /*
768  switch (i) {
769  // any other weird fitter specific conditions/ edge cases should go in here
770  }
771  */
772 
773  if (foundFitter)
774  {
775  if (printThoughts)
776  {
777  MACH3LOG_INFO("This is a {} file!", fitter);
778  }
779  inputFileDef.fitter = fitter;
780  return;
781  }
782  }
783 
784  // if we didn't return above then the fitter type wasn't found
785  if (printThoughts)
786  MACH3LOG_WARN("I don't know what kinda fitter this came from, will proceed with caution");
787  inputFileDef.fitter = "UNKNOWN_FITTER";
788 }
789 
790 void InputManager::fillFileData(InputFile &inputFileDef, const bool printThoughts) {
791  // load in the data in the file using the info gotten above
792  // EM: a lot of this is copy paste from above, could be better organised
793  if (printThoughts)
794  MACH3LOG_INFO("....getting data from file {}", inputFileDef.fileName);
795 
796  YAML::Node thisFitterSpec_config = _fitterSpecConfig[inputFileDef.fitter];
797 
798  // set the default post fit error type so we can read it as default later
799  inputFileDef.defaultErrorType =
800  Get<std::string>(thisFitterSpec_config["defaultPostFitErrorType"], __FILE__, __LINE__);
801 
802  // ########### First fill up the LLH vectors ############
803  for (const std::string LLHType : {"sample", "penalty", "total"})
804  {
805  if (!inputFileDef.hasLLHScans_map.at(LLHType))
806  continue;
807 
808  // vector of all the possible locations that we might find LLH scans for this type of LLH
809  YAML::Node testLLHConfig = thisFitterSpec_config[LLHType + "_LLH"];
810  const std::vector<std::string> testLLHRawLocations =
811  Get<std::vector<std::string>>(testLLHConfig["location"], __FILE__, __LINE__);
812 
813  // get the expected root object type of the llh scans
814  auto LLHObjType = Get<std::string>(thisFitterSpec_config["LLHObjectType"], __FILE__, __LINE__);
815  // EM: now get the objects from the file
816  for (const std::string &parameter : inputFileDef.availableParams_LLH)
817  {
818  std::shared_ptr<TObject> LLHObj = nullptr;
819 
820  // check the locations for the object
821  for (const std::string &rawLocation : testLLHRawLocations)
822  {
823  LLHObj = findRootObject(inputFileDef,
824  parseLocation(rawLocation, inputFileDef.fitter, kLLH, parameter));
825  // if we found it then break out of the loop
826  if (LLHObj != nullptr)
827  break;
828  }
829 
830  // double check that we actually found it.. just in case
831  if (LLHObj == nullptr)
832  {
833  MACH3LOG_ERROR("Hmmm, something seems to have gone wrong and I couldn't find the {} LLH scan for {} when attempting to read the data for it", LLHType, parameter);
834  MACH3LOG_ERROR("This will very likely cause segfaults and sadness");
835  }
836 
837  // now convert it to a TGraph
838  std::shared_ptr<TGraph> LLHGraph = std::make_shared<TGraph>();
839 
840  // EM: maybe have the type of the LLH object specified in the config to know what to downcast
841  // it to??
842  if (LLHObjType == "TH1D")
843  {
844  LLHGraph = std::make_shared<TGraph>(static_cast<TH1D*>(LLHObj.get()));
845  }
846 
847  else if (LLHObjType == "TGraph")
848  {
849  LLHGraph = std::shared_ptr<TGraph>(static_cast<TGraph*>(LLHObj->Clone()));
850  }
851 
852  else
853  {
854  MACH3LOG_CRITICAL("ERROR: uknown type of LLH object specified: {}", LLHObjType);
855  throw MaCh3Exception(__FILE__ , __LINE__ );
856  }
857 
858  inputFileDef.LLHScans_map[LLHType][parameter] = LLHGraph;
859  }
860  }
861 
862  // ####### Get the by sample LLH scans #######
863  for (const std::string &parameter : inputFileDef.availableParams_LLH)
864  {
865  for (const std::string &sample : _knownSamples)
866  {
867  findBySampleLLH(inputFileDef, parameter, inputFileDef.fitter, sample, true);
868  }
869  }
870 
871  // ####### Get the processed post fit errors #######
872  for (const std::string &parameter : inputFileDef.availableParams_postFitErrors)
873  {
874  auto availableErrorTypes = Get<std::vector<std::string>>(thisFitterSpec_config["AvailablePostFitErrorTypes"],
875  __FILE__, __LINE__);
876 
877  for (const std::string &errorType : availableErrorTypes)
878  {
879  findPostFitParamError(inputFileDef, parameter, inputFileDef.fitter, errorType, true);
880  }
881  }
882 
883  // ########## Get the MCMC related posteriors ###########
884  for (const std::string &parameter : inputFileDef.availableParams_MCMCchain)
885  {
886  findRawChainSteps(inputFileDef, parameter, inputFileDef.fitter, true);
887  }
888  for (const std::string &parameter : inputFileDef.availableParams_1dPosteriors)
889  {
890  find1dPosterior(inputFileDef, parameter, inputFileDef.fitter, true);
891  }
892 }
893 
894 std::vector<std::string> InputManager::TryToFindDefaultParamNames(const std::string& fileName) const {
895  std::vector<std::string> ParamNames;
896  auto file = std::unique_ptr<TFile>(TFile::Open(fileName.c_str()));
897  // MCMC processor output format
898  if (auto* ProcessorDir = dynamic_cast<TDirectory*>(file->Get("Post"));
899  ProcessorDir != nullptr)
900  {
901  TIter next(ProcessorDir->GetListOfKeys());
902 
903  while (auto* key = dynamic_cast<TKey*>(next())) {
904  ParamNames.emplace_back(key->GetName());
905  MACH3LOG_DEBUG("Adding name {}, assuming MCMC Processor file", ParamNames.back());
906  }
907 
908  return ParamNames;
909  }
910 
911  // LLH scan format
912  if (auto* llhDir = dynamic_cast<TDirectory*>(file->Get("Total_LLH"));
913  llhDir != nullptr)
914  {
915  TIter next(llhDir->GetListOfKeys());
916 
917  while (auto* key = dynamic_cast<TKey*>(next())) {
918  std::string name = key->GetName();
919  // Remove _total from hist name
920  const char suffix[] = "_full";
921  const std::size_t suffix_len = sizeof(suffix) - 1;
922  name.erase(name.size() - suffix_len);
923  ParamNames.push_back(std::move(name));
924  MACH3LOG_DEBUG("Adding name {}, assuming LLH scan file", ParamNames.back());
925  }
926 
927  return ParamNames;
928  }
929 
930  MACH3LOG_ERROR("You didn't specify any parameter in universalTranslator.yaml");
931  MACH3LOG_ERROR("Also you specified file I don't know format of so couldn't atomically find params");
932  throw MaCh3Exception(__FILE__, __LINE__);
933  return ParamNames;
934 }
935 
936 
937 } // namespace Plotting
938 } // namespace M3
#define MACH3LOG_CRITICAL
Definition: MaCh3Logger.h:38
#define MACH3LOG_DEBUG
Definition: MaCh3Logger.h:34
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:37
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:35
#define MACH3LOG_WARN
Definition: MaCh3Logger.h:36
#define M3OpenConfig(filename)
Macro to simplify calling LoadYaml with file and line info.
Definition: YamlHelper.h:590
void print(const std::string &printLevel="summary") const
Print out what this Inputmanager instance knows about.
std::unordered_map< std::string, std::vector< std::string > > _paramToTagsMap
Definition: InputManager.h:663
void addFile(const std::string &fileName)
Add a new InputFile object to this input manager.
void fillFileData(InputFile &inputFileDef, const bool printThoughts=true)
double getPostFitValue(const int fileNum, const std::string &paramName, std::string errorType="") const
Get the post fit value for a particular parameter from a particular input file.
std::vector< std::string > getTaggedValues(const std::vector< std::string > &values, const std::unordered_map< std::string, std::vector< std::string >> &tagMap, const std::vector< std::string > &tags, std::string checkType) const
std::vector< std::string > _knownSamples
Definition: InputManager.h:657
std::string getFitterSpecificParamName(const std::string &fitter, fileTypeEnum fileType, const std::string &parameter) const
Definition: InputManager.h:613
double getPostFitError(const int fileNum, const std::string &paramName, std::string errorType="") const
Get the post fit error for a particular parameter from a particular input file.
bool findRawChainSteps(InputFile &inputFileDef, const std::string &parameter, std::string &fitter, bool setInputBranch=false) const
bool find1dPosterior(InputFile &inputFileDef, const std::string &parameter, std::string &fitter, bool setFileData=false) const
std::shared_ptr< TObject > findRootObject(const InputFile &fileDef, const std::vector< std::string > &locationVec) const
std::vector< InputFile > _fileVec
Definition: InputManager.h:675
InputManager(const std::string &translationConfigName, const std::vector< std::string > &_fileNames)
Construct a new InputManager using specified fitter translation config file.
Definition: InputManager.cpp:6
std::vector< std::string > _knownParameters
Definition: InputManager.h:653
InputFile const & getFile(int fileId) const
Definition: InputManager.h:504
void fillFileInfo(InputFile &inputFileDef, const bool printThoughts=true)
std::vector< std::string > parseLocation(const std::string &locationString, std::string &fitter, fileTypeEnum fileType, const std::string &parameter="", const std::string &sample="", const std::string &parameter2="") const
std::string getFitterSpecificSampleName(const std::string &fitter, fileTypeEnum fileType, const std::string &sample) const
Definition: InputManager.h:627
std::vector< std::string > _knownFitters
Definition: InputManager.h:660
bool findBySampleLLH(InputFile &inputFileDef, const std::string &parameter, std::string &fitter, const std::string &sample, bool setInputFileScan=false)
std::vector< std::string > TryToFindDefaultParamNames(const std::string &fileNames) const
bool strEndsWith(const std::string &str, const std::string &ending) const
Definition: InputManager.h:643
bool findPostFitParamError(InputFile &inputFileDef, const std::string &parameter, std::string &fitter, const std::string &errorType, const bool setInputFileError=false)
std::unordered_map< std::string, std::vector< std::string > > _sampleToTagsMap
Definition: InputManager.h:665
bool getFitterSpecificParamOption(const std::string &fitter, const std::string &option, T &ret, const std::string &parameter) const
Definition: InputManager.h:599
Custom exception class used throughout MaCh3.
fileTypeEnum
Types of possible file that can be read.
Definition: InputManager.h:16
@ kMCMC
MCMC chain.
Definition: InputManager.h:19
@ kLLH
Log Likelihood scan.
Definition: InputManager.h:17
@ kPostFit
Processed post fit errors.
Definition: InputManager.h:18
Main namespace for MaCh3 software.
constexpr static const double _BAD_DOUBLE_
Default value used for double initialisation.
Definition: Core.h:53
TFile * Open(const std::string &Name, const std::string &Type, const std::string &File, const int Line)
Opens a ROOT file with the given name and mode.
Struct which wraps around the actual input file and also holds general information,...
Definition: InputManager.h:36
std::unordered_map< std::string, bool > availableParams_map_1dPosteriors
Definition: InputManager.h:182
std::unordered_map< std::string, std::unordered_map< std::string, bool > > availableParams_map_LLH
Definition: InputManager.h:139
std::shared_ptr< TFile > file
Pointer to the underlying file for this InputFile instance.
Definition: InputManager.h:116
std::string defaultErrorType
Definition: InputManager.h:169
bool has1dPosteriors
Whether or not the file has processed 1d posteriors.
Definition: InputManager.h:173
bool hasPostFitErrors
Whether or not this file contains any processed post fit errors.
Definition: InputManager.h:160
std::vector< std::string > availableParams_MCMCchain
Definition: InputManager.h:185
int nMCMCentries
The number of steps in the MCMC chain.
Definition: InputManager.h:178
std::unordered_map< std::string, double * > MCMCstepParamsMap
Definition: InputManager.h:187
std::unordered_map< std::string, bool > availableParams_map_MCMCchain
whether or not specific parameters exist in the MCMC posterior chain
Definition: InputManager.h:181
bool hasLLHScans
Whether or not this file contains any log likelihood scans.
Definition: InputManager.h:129
std::unordered_map< std::string, std::shared_ptr< TGraph > > posteriors1d_map
Definition: InputManager.h:190
std::unordered_map< std::string, std::unordered_map< std::string, std::shared_ptr< TGraph > > > LLHScans_map
Definition: InputManager.h:136
std::string fileName
The location of the underlying file.
Definition: InputManager.h:117
std::vector< std::string > availableParams_postFitErrors
The parameters that this file has post fit errors for.
Definition: InputManager.h:162
std::unordered_map< std::string, std::unordered_map< std::string, std::shared_ptr< TGraph > > > LLHScansBySample_map
Definition: InputManager.h:152
std::unordered_map< std::string, std::unordered_map< std::string, double > > postFitValues
Definition: InputManager.h:167
bool hasMCMCchain
Whether or not the file has unprocessed MCMC chain steps.
Definition: InputManager.h:175
std::unordered_map< std::string, std::unordered_map< std::string, double > > postFitErrors
Definition: InputManager.h:164
std::vector< std::string > availableParams_1dPosteriors
Definition: InputManager.h:184
std::unique_ptr< MCMCProcessor > mcmcProc
ptr to an MCMCProcessor instance to be used if this is a MaCh3 input file
Definition: InputManager.h:113
std::vector< std::string > availableParams_LLH
The parameters that this file contains likelihood scans for.
Definition: InputManager.h:131
std::vector< std::string > availableSamples_LLH
Definition: InputManager.h:149
std::string fitter
Which fitter this file came from, detected by InputManager::fillFileInfo().
Definition: InputManager.h:119
std::unordered_map< std::string, std::unordered_map< std::string, bool > > availableParams_map_LLHBySample
Definition: InputManager.h:155
std::unordered_map< std::string, bool > hasLLHScans_map
Definition: InputManager.h:133