AliPhysics  dab84fb (dab84fb)
AliYAMLConfiguration.h
Go to the documentation of this file.
1 #ifndef ALIYAMLCONFIGURATION_H
2 #define ALIYAMLCONFIGURATION_H
3 
4 // CINT can't handle the yaml header because it has c++11!
5 #if !(defined(__CINT__) || defined(__MAKECINT__))
6 #include <yaml-cpp/yaml.h>
7 #endif
8 
9 #include <string>
10 #include <vector>
11 #include <ostream>
12 
13 #include <TObject.h>
14 #include <TString.h>
15 
16 #include <AliLog.h>
17 
117 #if !(defined(__CINT__) || defined(__MAKECINT__))
118 namespace YAML {
119 template<>
120  struct convert<TString> {
121  static Node encode(const TString & str) {
122  return Node(str.Data());
123  }
124  static bool decode(const Node & node, TString & str) {
125  if (!node.IsScalar()) {
126  return false;
127  }
128  str = node.Scalar();
129  return true;
130  }
131  };
132 }
133 #endif
134 
135 // operator<< has to be forward declared carefully to stay in the global namespace so that it works with CINT.
136 // For generally how to keep the operator in the global namespace, See: https://stackoverflow.com/a/38801633
137 namespace PWG { namespace Tools { class AliYAMLConfiguration; } }
138 std::ostream & operator<< (std::ostream &in, const PWG::Tools::AliYAMLConfiguration &myTask);
139 
140 namespace PWG {
141 namespace Tools {
142 
144  public:
145  AliYAMLConfiguration(const std::string prefixString = "AliEmcalCorrection", const std::string delimiterCharacter = ":");
147 
151  bool Initialize();
152  bool Reinitialize();
158  int AddEmptyConfiguration(const std::string & configurationName);
160  int AddConfiguration(std::string configurationFilename, std::string configurationName = "");
161  #if !(defined(__CINT__) || defined(__MAKECINT__))
162  int AddConfiguration(const YAML::Node node, std::string configurationName = "");
168  bool DoesConfigurationExist(const int i) const { return i >= 0 && static_cast<const unsigned int>(i) < fConfigurations.size(); }
169  bool DoesConfigurationExist(const std::string & name) const { return DoesConfigurationExist(GetConfigurationIndexFromName(name, fConfigurations)); }
170  const std::pair<std::string, YAML::Node> & GetConfiguration(const int i) const { return fConfigurations.at(i); }
171  const std::pair<std::string, YAML::Node> & GetConfiguration(const std::string & name) const { return GetConfiguration(GetConfigurationIndexFromName(name, fConfigurations)); }
172  std::pair<std::string, YAML::Node> & GetConfiguration(const int i) { return fConfigurations.at(i); }
173  std::pair<std::string, YAML::Node> & GetConfiguration(const std::string & name) { return GetConfiguration(GetConfigurationIndexFromName(name, fConfigurations)); }
179  std::string GetConfigurationNameFromIndex(const unsigned int i) const { return fConfigurations.at(i).first; }
180  int GetConfigurationIndexFromName(const std::string & name) const { return GetConfigurationIndexFromName(name, fConfigurations); }
186  bool RemoveConfiguration(const unsigned int i);
187  bool RemoveConfiguration(const std::string & name) { return RemoveConfiguration(GetConfigurationIndexFromName(name, fConfigurations)); }
193  // Helper functions to retrieve property values
194  template<typename T>
195  bool GetProperty(std::vector<std::string> propertyPath, const std::string & propertyName, T & property, const bool requiredProperty) const;
196  template<typename T>
197  bool GetProperty(const std::vector<std::string> propertyPath, T & property, const bool requiredProperty) const;
198  // Retrieve property driver function.
199  template<typename T>
200  bool GetProperty(std::string propertyName, T & property, const bool requiredProperty = true) const;
206  // Write property driver function.
207  template<typename T>
208  bool WriteProperty(std::string propertyName, T & property, std::string configurationName = "");
210  #endif
211 
215  bool WriteConfiguration(const std::string & filename, const unsigned int i) const;
216  bool WriteConfiguration(const std::string & filename, const std::string & configurationName) const;
222  bool CompareConfigurations(const int config1, const int config2) const;
223  bool CompareConfigurations(const int config1, const std::string & config2) const { return CompareConfigurations(config1, GetConfigurationIndexFromName(config2, fConfigurations)); }
224  bool CompareConfigurations(const std::string & config1, const std::string & config2) const { return CompareConfigurations(GetConfigurationIndexFromName(config1, fConfigurations), GetConfigurationIndexFromName(config2, fConfigurations)); }
225 
231  std::string toString(const int index = -1) const;
232  std::ostream & Print(std::ostream &in, const int index = -1) const;
233  std::ostream & Print(std::ostream &in, const std::string & configurationName) const;
234  friend std::ostream & ::operator<< (std::ostream &in, const AliYAMLConfiguration &myTask);
235  void Print(Option_t* /* opt */ = "") const;
238  protected:
239 
240  // Utility functions
241  // File utilities
242  inline bool DoesFileExist(const std::string & filename) const;
243  void SetupReadingConfigurationFilePath(std::string & filename, const std::string & fileIdentifier) const;
244  void WriteConfigurationToFilePath(const std::string & localFilename, std::string filename) const;
245  #if !(defined(__CINT__) || defined(__MAKECINT__))
246  // Printing
247  void PrintConfiguration(std::ostream & stream, const std::pair<std::string, YAML::Node> & configPair) const;
248  #endif
249  // Configuration utilities
250  template<typename T>
251  unsigned int GetConfigurationIndexFromName(const std::string & name, const std::vector<std::pair<std::string, T>> & configurations) const;
252 
253  bool IsSharedValue(std::string & value) const;
254  #if !(defined(__CINT__) || defined(__MAKECINT__))
255  template<typename T>
256  auto PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const T & property, int) const -> decltype(tempMessage << property, void());
257  template<typename T>
258  auto PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const std::vector <T> & property, int) const -> decltype(property.begin(), property.end(), tempMessage << std::declval<T>(), void());
259  template<typename T>
260  void PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const T & property, long) const;
261  template<typename T>
262  void PrintRetrievedPropertyValue(std::stringstream & tempMessage, const T & property) const;
263 
264  template<typename T>
265  bool GetPropertyFromNode(const YAML::Node & node, std::string propertyName, T & property) const;
266  template<typename T>
267  bool GetProperty(YAML::Node & node, YAML::Node & sharedParametersNode, const std::string & configurationName, std::string propertyName, T & property) const;
268 
269  template<typename T>
270  void WriteValue(YAML::Node & node, std::string propertyName, T & proeprty);
271 
272  std::vector<std::pair<std::string, YAML::Node> > fConfigurations;
273  #endif
274  std::vector<std::pair<std::string, std::string> > fConfigurationsStrings;
275 
277  std::string fPrefixString;
278  std::string fDelimiter;
279 
281  ClassDef(AliYAMLConfiguration, 1); // YAML Configuration
283 };
284 
285 #if !(defined(__CINT__) || defined(__MAKECINT__))
286 
296 template<typename T>
297 auto AliYAMLConfiguration::PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const T & property, int) const -> decltype(tempMessage << property, void())
298 {
299  tempMessage << " with value \"" << property << "\"";
300 }
301 
310 template<typename T>
311 auto AliYAMLConfiguration::PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const std::vector <T> & property, int) const -> decltype(property.begin(), property.end(), tempMessage << std::declval<T>(), void())
312 {
313  tempMessage << " with value(s):";
314  for (auto it = property.begin(); it != property.end(); it++) {
315  tempMessage << "\n\t- " << *it;
316  }
317 }
318 
330 template<typename T>
331 void AliYAMLConfiguration::PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const T & property, long) const
332 {
333  // Cannot easily print these types, so just note that is the case!
334  tempMessage << " with a value that cannot be trivially printed";
335 }
336 
348 template<typename T>
349 void AliYAMLConfiguration::PrintRetrievedPropertyValue(std::stringstream & tempMessage, const T & property) const
350 {
351  // By passing zero, it will first lookup the int, and then the long
352  AliYAMLConfiguration::PrintRetrievedPropertyValueImpl(tempMessage, property, 0);
353 }
354 
364 template<typename T>
365 bool AliYAMLConfiguration::GetPropertyFromNode(const YAML::Node & node, std::string propertyName, T & property) const
366 {
367  if (node[propertyName])
368  {
369  property = node[propertyName].as<T>();
370  return true;
371  }
372  return false;
373 }
374 
386 template<typename T>
387 bool AliYAMLConfiguration::GetProperty(std::vector <std::string> propertyPath, const std::string & propertyName, T & property, const bool requiredProperty) const
388 {
389  propertyPath.push_back(propertyName);
390  return GetProperty(propertyPath, property, requiredProperty);
391 }
392 
403 template<typename T>
404 bool AliYAMLConfiguration::GetProperty(const std::vector <std::string> propertyPath, T & property, const bool requiredProperty) const
405 {
406  // Combine the requested names together
407  std::string requestedName = "";
408  for (auto & str : propertyPath)
409  {
410  if (requestedName.length() > 0) {
411  requestedName += ":" + str;
412  }
413  else {
414  requestedName = str;
415  }
416  }
417 
418  // Pass on the properly requested call
419  return GetProperty(requestedName, property, requiredProperty);
420 }
421 
433 template<typename T>
434 bool AliYAMLConfiguration::GetProperty(std::string propertyName, T & property, const bool requiredProperty) const
435 {
436  // Remove the prefix string if in name
437  std::size_t prefixStringLocation = propertyName.find(fPrefixString);
438  if (prefixStringLocation != std::string::npos)
439  {
440  // Remove the prefix string
441  propertyName.erase(prefixStringLocation, prefixStringLocation + fPrefixString.length());
442  }
443 
444  bool setProperty = false;
445  for (auto configPair : fConfigurations)
446  {
447  if (setProperty == true) {
448  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Property \"" << propertyName << "\" found!\n";
449  break;
450  }
451 
452  // IsNull checks is a node is empty. A node is empty if it is created.
453  // IsDefined checks if the node that was requested was not actually created.
454  if (configPair.second.IsNull() != true)
455  {
456  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Looking for parameter \"" << propertyName << "\" in \"" << configPair.first << "\" configuration\n";
457  // NOTE: This may not exist, but that is entirely fine.
458  YAML::Node sharedParameters = configPair.second["sharedParameters"];
459  setProperty = GetProperty(configPair.second, sharedParameters, configPair.first, propertyName, property);
460  }
461  }
462 
463  if (setProperty != true && requiredProperty == true)
464  {
465  std::stringstream message;
466  message << "Failed to retrieve required property \""
467  << propertyName << "\" from available configurations!" << std::endl;
468  AliFatalGeneral("AliYAMLConfiguration", message.str().c_str());
469  }
470 
471  // Return whether the value was actually set
472  return setProperty;
473 }
474 
497 template<typename T>
498 bool AliYAMLConfiguration::GetProperty(YAML::Node & node, YAML::Node & sharedParametersNode, const std::string & configurationName, std::string propertyName, T & property) const
499 {
500  // Used as a buffer for printing complicated messages
501  std::stringstream tempMessage;
502 
503  bool returnValue = false;
504 
505  const std::string specializationDelimiter = "_";
506  size_t delimiterPosition = 0;
507  std::string tempPropertyName = propertyName;
508 
509  if ((delimiterPosition = tempPropertyName.find(fDelimiter)) != std::string::npos)
510  {
511  std::string nodeName = tempPropertyName.substr(0, delimiterPosition);
512  tempPropertyName.erase(0, delimiterPosition + fDelimiter.length());
513 
514  // Attempt to use the node name
515  if (node[nodeName].IsDefined() == true)
516  {
517  // Retrieve node and then recurse
518  YAML::Node tempNode = node[nodeName];
519  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Attempting to retrieving property \"" << tempPropertyName << "\" by going a node deeper with node \"" << nodeName << "\".\n";
520  returnValue = GetProperty(tempNode, sharedParametersNode, configurationName, tempPropertyName, property);
521  }
522 
523  // Check for the specialization if the nodeName is undefined.
524  // Alternatively, if the value was not returned successfully, we should also check for the specialization
525  // such as inheritnace for input objects.
526  if (node[nodeName].IsDefined() == false || returnValue == false)
527  {
528  // Check for specialization
529  if ((delimiterPosition = nodeName.find(specializationDelimiter)) != std::string::npos)
530  {
531  std::string specializationNodeName = nodeName.substr(0, delimiterPosition);
532  YAML::Node tempNode = node[specializationNodeName];
533  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Attempting to retrieving property \"" << tempPropertyName << "\" by going a node deeper through dropping the specializtion and using node \"" << specializationNodeName << "\".\n";
534  returnValue = GetProperty(tempNode, sharedParametersNode, configurationName, tempPropertyName, property);
535  }
536  else {
537  returnValue = false;
538  }
539  }
540  }
541  else
542  {
543  // Check if node exists!
544  if (node[propertyName])
545  {
546  // Handle shared parameters
547  bool isShared = false;
548  // Will contain the name of the property in the sharedParameters section that should be retrieved
549  // if it is requested through the user configuration.
550  std::string sharedValueName = "";
551  // Necessary because it fails on vectors and other complex objects that are YAML sequences.
552  if (std::is_arithmetic<T>::value || std::is_same<T, std::string>::value || std::is_same<T, bool>::value)
553  {
554  // Retrieve value as string to check for shared value
555  sharedValueName = node[propertyName].as<std::string>();
556  // Check for a shared value
557  isShared = IsSharedValue(sharedValueName);
558  }
559 
560  // Setup printable message
561  tempMessage.str("");
562  tempMessage << "property \""
563  << propertyName
564  << "\" using " << ( isShared ? "\"sharedParameters:" + sharedValueName + "\" in " : "" )
565  << "values from the " << configurationName << " configuration";
566 
567  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Retrieveing " << tempMessage.str() << "\n";
568 
569  // Retrieve result
570  bool retrievalResult = false;
571  if (isShared == true) {
572  // Retrieve from the shared parameter node directly.
573  retrievalResult = GetPropertyFromNode(sharedParametersNode, sharedValueName, property);
574  }
575  else {
576  retrievalResult = GetPropertyFromNode(node, propertyName, property);
577  }
578 
579  // Inform about the result
580  if (retrievalResult == true) {
581  // Add the retrieved value to the message (only if trivially printable)
582  AliYAMLConfiguration::PrintRetrievedPropertyValue(tempMessage, property);
583  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Succeeded in retrieveing " << tempMessage.str() << "\n";
584  returnValue = true;
585  }
586  else {
587  returnValue = false;
588  }
589  }
590  }
591 
592  return returnValue;
593 }
594 
605 template<typename T>
606 bool AliYAMLConfiguration::WriteProperty(std::string propertyName, T & property, std::string configurationName)
607 {
608  unsigned int configurationIndex = 0;
609  if (configurationName != "")
610  {
611  configurationIndex = GetConfigurationIndexFromName(configurationName, fConfigurations);
612  }
613 
614  if (fConfigurations.size() == 0) {
615  AliErrorStream() << "No configurations available! Property will not be written!\n";
616  return false;
617  }
618 
619  std::pair<std::string, YAML::Node> & configPair = fConfigurations.at(configurationIndex);
620 
621  WriteValue(configPair.second, propertyName, property);
622  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Final Node:\n" << configPair.second << "\n";
623 
624  return true;
625 }
626 
634 template<typename T>
635 void AliYAMLConfiguration::WriteValue(YAML::Node & node, std::string propertyName, T & property)
636 {
637  // Find the node name we are interested in
638  // Derived from: https://stackoverflow.com/a/14266139
639  const std::string delimiter = ":";
640  size_t delimiterPosition = 0;
641  std::string tempPropertyName = propertyName;
642 
643  if ((delimiterPosition = tempPropertyName.find(delimiter)) != std::string::npos)
644  {
645  std::string nodeName = tempPropertyName.substr(0, delimiterPosition);
646  tempPropertyName.erase(0, delimiterPosition + delimiter.length());
647  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "nodeName: " << nodeName << "\n";
648  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Node Before:\n" << node << "\n";
649  if (node[nodeName].IsDefined()) {
650  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Using existing node\n";
651  YAML::Node tempNode = node[nodeName];
652  WriteValue(tempNode, tempPropertyName, property);
653  }
654  else {
655  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Creating new node\n";
656  YAML::Node tempNode;
657  node[nodeName] = tempNode;
658  WriteValue(tempNode, tempPropertyName, property);
659  }
660  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Node After:\n" << node << "\n";
661  }
662  else {
663  // We have finished the recursion. Now we need to save the actual property.
664  node[propertyName] = property;
665  }
666 }
667 
668 #endif
669 
679 template<typename T>
680 unsigned int AliYAMLConfiguration::GetConfigurationIndexFromName(const std::string & name, const std::vector<std::pair<std::string, T>> & configurations) const
681 {
682  int index = -1;
683  for (const auto & configPair : configurations)
684  {
685  if (configPair.first == name) {
686  // Retrieve index
687  // See: https://stackoverflow.com/a/10962459
688  index = std::addressof(configPair) - std::addressof(configurations[0]);
689  break;
690  }
691  }
692 
693  return index;
694 }
695 
696 } // namespace Tools
697 } // namespace PWG
698 
699 #endif /* ALIYAMLCONFIGURATION_H */
bool RemoveConfiguration(const std::string &name)
const char * filename
Definition: TestFCM.C:1
void Print(std::ostream &o, const char *name, Double_t dT, Double_t dVM, Double_t alldT, Double_t alldVM)
Definition: PlotSysInfo.C:121
bool CompareConfigurations(const int config1, const std::string &config2) const
const std::pair< std::string, YAML::Node > & GetConfiguration(const int i) const
bool fInitialized
True if the configurations have been initialized.
bool DoesConfigurationExist(const int i) const
int GetConfigurationIndexFromName(const std::string &name) const
UShort_t T(UShort_t m, UShort_t t)
Definition: RingBits.C:60
const std::pair< std::string, YAML::Node > & GetConfiguration(const std::string &name) const
std::string fDelimiter
Delimiter character to separate each level of the request.
bool DoesConfigurationExist(const std::string &name) const
std::ostream & operator<<(std::ostream &in, const PWG::Tools::AliYAMLConfiguration &myTask)
Namespace for PWG framework classes.
std::string fPrefixString
Contains the prefix of any names base node names which should be removed.
std::vector< std::pair< std::string, YAML::Node > > fConfigurations
! Contains all YAML configurations. The first element has the highest precedence. ...
bool CompareConfigurations(const std::string &config1, const std::string &config2) const
static Node encode(const TString &str)
std::pair< std::string, YAML::Node > & GetConfiguration(const int i)
std::vector< std::pair< std::string, std::string > > fConfigurationsStrings
Contains all YAML configurations as strings so that they can be streamed.
YAML configuration class for AliPhysics.
static bool decode(const Node &node, TString &str)
const char Option_t
Definition: External.C:48
std::string GetConfigurationNameFromIndex(const unsigned int i) const
std::pair< std::string, YAML::Node > & GetConfiguration(const std::string &name)