AliPhysics  8773fe4 (8773fe4)
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 
123 #if !(defined(__CINT__) || defined(__MAKECINT__))
124 namespace YAML {
125 template<>
126  struct convert<TString> {
127  static Node encode(const TString & str) {
128  return Node(str.Data());
129  }
130  static bool decode(const Node & node, TString & str) {
131  if (!node.IsScalar()) {
132  return false;
133  }
134  str = node.Scalar();
135  return true;
136  }
137  };
138 }
139 #endif
140 
151 template <typename It>
152 class Range
153 {
154  It b, e;
155 
156  public:
157  Range(It b, It e) : b(b), e(e) {}
158  It begin() const { return b; }
159  It end() const { return e; }
160 };
161 
162 template <typename ORange, typename OIt = decltype(std::begin(std::declval<ORange>())),
163  typename It = std::reverse_iterator<OIt>>
164 Range<It> reverse(ORange&& originalRange)
165 {
166  return Range<It>(It(std::end(originalRange)), It(std::begin(originalRange)));
167 }
168 
169 // operator<< has to be forward declared carefully to stay in the global namespace so that it works with CINT.
170 // For generally how to keep the operator in the global namespace, See: https://stackoverflow.com/a/38801633
171 namespace PWG { namespace Tools { class AliYAMLConfiguration; } }
172 std::ostream & operator<< (std::ostream &in, const PWG::Tools::AliYAMLConfiguration &myTask);
173 
174 namespace PWG {
175 namespace Tools {
176 
178  public:
179  AliYAMLConfiguration(const std::string prefixString = "AliEmcalCorrection", const std::string delimiterCharacter = ":");
181 
185  bool Initialize();
186  bool Reinitialize();
192  int AddEmptyConfiguration(const std::string & configurationName);
194  int AddConfiguration(std::string configurationFilename, std::string configurationName = "");
195  #if !(defined(__CINT__) || defined(__MAKECINT__))
196  int AddConfiguration(const YAML::Node node, std::string configurationName = "");
202  bool DoesConfigurationExist(const int i) const { return i >= 0 && static_cast<const unsigned int>(i) < fConfigurations.size(); }
203  bool DoesConfigurationExist(const std::string & name) const { return DoesConfigurationExist(GetConfigurationIndexFromName(name, fConfigurations)); }
204  const std::pair<std::string, YAML::Node> & GetConfiguration(const int i) const { return fConfigurations.at(i); }
205  const std::pair<std::string, YAML::Node> & GetConfiguration(const std::string & name) const { return GetConfiguration(GetConfigurationIndexFromName(name, fConfigurations)); }
206  std::pair<std::string, YAML::Node> & GetConfiguration(const int i) { return fConfigurations.at(i); }
207  std::pair<std::string, YAML::Node> & GetConfiguration(const std::string & name) { return GetConfiguration(GetConfigurationIndexFromName(name, fConfigurations)); }
213  std::string GetConfigurationNameFromIndex(const unsigned int i) const { return fConfigurations.at(i).first; }
214  int GetConfigurationIndexFromName(const std::string & name) const { return GetConfigurationIndexFromName(name, fConfigurations); }
220  bool RemoveConfiguration(const unsigned int i);
221  bool RemoveConfiguration(const std::string & name) { return RemoveConfiguration(GetConfigurationIndexFromName(name, fConfigurations)); }
227  // Helper functions to retrieve property values
228  template<typename T>
229  bool GetProperty(std::vector<std::string> propertyPath, const std::string & propertyName, T & property, const bool requiredProperty) const;
230  template<typename T>
231  bool GetProperty(const std::vector<std::string> propertyPath, T & property, const bool requiredProperty) const;
232  // Retrieve property driver function.
233  template<typename T>
234  bool GetProperty(std::string propertyName, T & property, const bool requiredProperty = true) const;
240  // Write property driver function.
241  template<typename T>
242  bool WriteProperty(std::string propertyName, T & property, std::string configurationName = "");
244  #endif
245 
249  bool WriteConfiguration(const std::string & filename, const unsigned int i) const;
250  bool WriteConfiguration(const std::string & filename, const std::string & configurationName) const;
256  bool CompareConfigurations(const int config1, const int config2) const;
257  bool CompareConfigurations(const int config1, const std::string & config2) const { return CompareConfigurations(config1, GetConfigurationIndexFromName(config2, fConfigurations)); }
258  bool CompareConfigurations(const std::string & config1, const std::string & config2) const { return CompareConfigurations(GetConfigurationIndexFromName(config1, fConfigurations), GetConfigurationIndexFromName(config2, fConfigurations)); }
259 
265  std::string toString(const int index = -1) const;
266  std::ostream & Print(std::ostream &in, const int index = -1) const;
267  std::ostream & Print(std::ostream &in, const std::string & configurationName) const;
268  friend std::ostream & ::operator<< (std::ostream &in, const AliYAMLConfiguration &myTask);
269  void Print(Option_t* /* opt */ = "") const;
272  protected:
273 
274  // Utility functions
275  // File utilities
276  inline bool DoesFileExist(const std::string & filename) const;
277  void SetupReadingConfigurationFilePath(std::string & filename, const std::string & fileIdentifier) const;
278  void WriteConfigurationToFilePath(const std::string & localFilename, std::string filename) const;
279  #if !(defined(__CINT__) || defined(__MAKECINT__))
280  // Printing
281  void PrintConfiguration(std::ostream & stream, const std::pair<std::string, YAML::Node> & configPair) const;
282  #endif
283  // Configuration utilities
284  template<typename T>
285  unsigned int GetConfigurationIndexFromName(const std::string & name, const std::vector<std::pair<std::string, T>> & configurations) const;
286 
287  bool IsSharedValue(std::string & value) const;
288  #if !(defined(__CINT__) || defined(__MAKECINT__))
289  template<typename T>
290  auto PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const T & property, int) const -> decltype(tempMessage << property, void());
291  template<typename T>
292  auto PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const std::vector <T> & property, int) const -> decltype(property.begin(), property.end(), tempMessage << std::declval<T>(), void());
293  template<typename T>
294  void PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const T & property, long) const;
295  template<typename T>
296  void PrintRetrievedPropertyValue(std::stringstream & tempMessage, const T & property) const;
297 
298  template<typename T>
299  bool GetPropertyFromNode(const YAML::Node & node, std::string propertyName, T & property) const;
300  template<typename T>
301  bool GetProperty(YAML::Node & node, YAML::Node & sharedParametersNode, const std::string & configurationName, std::string propertyName, T & property) const;
302 
303  template<typename T>
304  void WriteValue(YAML::Node & node, std::string propertyName, T & proeprty);
305 
306  std::vector<std::pair<std::string, YAML::Node> > fConfigurations;
307  #endif
308  std::vector<std::pair<std::string, std::string> > fConfigurationsStrings;
309 
311  std::string fPrefixString;
312  std::string fDelimiter;
313 
315  ClassDef(AliYAMLConfiguration, 1); // YAML Configuration
317 };
318 
319 #if !(defined(__CINT__) || defined(__MAKECINT__))
320 
330 template<typename T>
331 auto AliYAMLConfiguration::PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const T & property, int) const -> decltype(tempMessage << property, void())
332 {
333  tempMessage << " with value \"" << property << "\"";
334 }
335 
344 template<typename T>
345 auto AliYAMLConfiguration::PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const std::vector <T> & property, int) const -> decltype(property.begin(), property.end(), tempMessage << std::declval<T>(), void())
346 {
347  tempMessage << " with value(s):";
348  for (auto it = property.begin(); it != property.end(); it++) {
349  tempMessage << "\n\t- " << *it;
350  }
351 }
352 
364 template<typename T>
365 void AliYAMLConfiguration::PrintRetrievedPropertyValueImpl(std::stringstream & tempMessage, const T & property, long) const
366 {
367  // Cannot easily print these types, so just note that is the case!
368  tempMessage << " with a value that cannot be trivially printed";
369 }
370 
382 template<typename T>
383 void AliYAMLConfiguration::PrintRetrievedPropertyValue(std::stringstream & tempMessage, const T & property) const
384 {
385  // By passing zero, it will first lookup the int, and then the long
386  AliYAMLConfiguration::PrintRetrievedPropertyValueImpl(tempMessage, property, 0);
387 }
388 
398 template<typename T>
399 bool AliYAMLConfiguration::GetPropertyFromNode(const YAML::Node & node, std::string propertyName, T & property) const
400 {
401  if (node[propertyName])
402  {
403  property = node[propertyName].as<T>();
404  return true;
405  }
406  return false;
407 }
408 
420 template<typename T>
421 bool AliYAMLConfiguration::GetProperty(std::vector <std::string> propertyPath, const std::string & propertyName, T & property, const bool requiredProperty) const
422 {
423  propertyPath.push_back(propertyName);
424  return GetProperty(propertyPath, property, requiredProperty);
425 }
426 
437 template<typename T>
438 bool AliYAMLConfiguration::GetProperty(const std::vector <std::string> propertyPath, T & property, const bool requiredProperty) const
439 {
440  // Combine the requested names together
441  std::string requestedName = "";
442  for (auto & str : propertyPath)
443  {
444  if (requestedName.length() > 0) {
445  requestedName += ":" + str;
446  }
447  else {
448  requestedName = str;
449  }
450  }
451 
452  // Pass on the properly requested call
453  return GetProperty(requestedName, property, requiredProperty);
454 }
455 
467 template<typename T>
468 bool AliYAMLConfiguration::GetProperty(std::string propertyName, T & property, const bool requiredProperty) const
469 {
470  // Remove the prefix string if in name
471  std::size_t prefixStringLocation = propertyName.find(fPrefixString);
472  if (prefixStringLocation != std::string::npos)
473  {
474  // Remove the prefix string
475  propertyName.erase(prefixStringLocation, prefixStringLocation + fPrefixString.length());
476  }
477 
478  bool setProperty = false;
479  // Search in reverse so it is possible to override configuration values.
480  for (auto configPair : reverse(fConfigurations))
481  {
482  if (setProperty == true) {
483  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Property \"" << propertyName << "\" found!\n";
484  break;
485  }
486 
487  // IsNull checks is a node is empty. A node is empty if it is created.
488  // IsDefined checks if the node that was requested was not actually created.
489  if (configPair.second.IsNull() != true)
490  {
491  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Looking for parameter \"" << propertyName << "\" in \"" << configPair.first << "\" configuration\n";
492  // NOTE: This may not exist, but that is entirely fine.
493  YAML::Node sharedParameters = configPair.second["sharedParameters"];
494  setProperty = GetProperty(configPair.second, sharedParameters, configPair.first, propertyName, property);
495  }
496  }
497 
498  if (setProperty != true && requiredProperty == true)
499  {
500  std::stringstream message;
501  message << "Failed to retrieve required property \""
502  << propertyName << "\" from available configurations!" << std::endl;
503  AliFatalGeneral("AliYAMLConfiguration", message.str().c_str());
504  }
505 
506  // Return whether the value was actually set
507  return setProperty;
508 }
509 
532 template<typename T>
533 bool AliYAMLConfiguration::GetProperty(YAML::Node & node, YAML::Node & sharedParametersNode, const std::string & configurationName, std::string propertyName, T & property) const
534 {
535  // Used as a buffer for printing complicated messages
536  std::stringstream tempMessage;
537 
538  bool returnValue = false;
539 
540  const std::string specializationDelimiter = "_";
541  size_t delimiterPosition = 0;
542  std::string tempPropertyName = propertyName;
543 
544  if ((delimiterPosition = tempPropertyName.find(fDelimiter)) != std::string::npos)
545  {
546  std::string nodeName = tempPropertyName.substr(0, delimiterPosition);
547  tempPropertyName.erase(0, delimiterPosition + fDelimiter.length());
548 
549  // Attempt to use the node name
550  if (node[nodeName].IsDefined() == true)
551  {
552  // Retrieve node and then recurse
553  YAML::Node tempNode = node[nodeName];
554  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Attempting to retrieving property \"" << tempPropertyName << "\" by going a node deeper with node \"" << nodeName << "\".\n";
555  returnValue = GetProperty(tempNode, sharedParametersNode, configurationName, tempPropertyName, property);
556  }
557 
558  // Check for the specialization if the nodeName is undefined.
559  // Alternatively, if the value was not returned successfully, we should also check for the specialization
560  // such as inheritnace for input objects.
561  if (node[nodeName].IsDefined() == false || returnValue == false)
562  {
563  // Check for specialization
564  if ((delimiterPosition = nodeName.find(specializationDelimiter)) != std::string::npos)
565  {
566  std::string specializationNodeName = nodeName.substr(0, delimiterPosition);
567  YAML::Node tempNode = node[specializationNodeName];
568  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Attempting to retrieving property \"" << tempPropertyName << "\" by going a node deeper through dropping the specializtion and using node \"" << specializationNodeName << "\".\n";
569  returnValue = GetProperty(tempNode, sharedParametersNode, configurationName, tempPropertyName, property);
570  }
571  else {
572  returnValue = false;
573  }
574  }
575  }
576  else
577  {
578  // Check if node exists!
579  if (node[propertyName])
580  {
581  // Handle shared parameters
582  bool isShared = false;
583  // Will contain the name of the property in the sharedParameters section that should be retrieved
584  // if it is requested through the user configuration.
585  std::string sharedValueName = "";
586  // Necessary because it fails on vectors and other complex objects that are YAML sequences.
587  if (std::is_arithmetic<T>::value || std::is_same<T, std::string>::value || std::is_same<T, bool>::value)
588  {
589  // Retrieve value as string to check for shared value
590  sharedValueName = node[propertyName].as<std::string>();
591  // Check for a shared value
592  isShared = IsSharedValue(sharedValueName);
593  }
594 
595  // Setup printable message
596  tempMessage.str("");
597  tempMessage << "property \""
598  << propertyName
599  << "\" using " << ( isShared ? "\"sharedParameters:" + sharedValueName + "\" in " : "" )
600  << "values from the " << configurationName << " configuration";
601 
602  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Retrieveing " << tempMessage.str() << "\n";
603 
604  // Retrieve result
605  bool retrievalResult = false;
606  if (isShared == true) {
607  // Retrieve from the shared parameter node directly.
608  retrievalResult = GetPropertyFromNode(sharedParametersNode, sharedValueName, property);
609  }
610  else {
611  retrievalResult = GetPropertyFromNode(node, propertyName, property);
612  }
613 
614  // Inform about the result
615  if (retrievalResult == true) {
616  // Add the retrieved value to the message (only if trivially printable)
617  AliYAMLConfiguration::PrintRetrievedPropertyValue(tempMessage, property);
618  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Succeeded in retrieveing " << tempMessage.str() << "\n";
619  returnValue = true;
620  }
621  else {
622  returnValue = false;
623  }
624  }
625  }
626 
627  return returnValue;
628 }
629 
640 template<typename T>
641 bool AliYAMLConfiguration::WriteProperty(std::string propertyName, T & property, std::string configurationName)
642 {
643  unsigned int configurationIndex = 0;
644  if (configurationName != "")
645  {
646  configurationIndex = GetConfigurationIndexFromName(configurationName, fConfigurations);
647  }
648 
649  if (fConfigurations.size() == 0) {
650  AliErrorStream() << "No configurations available! Property will not be written!\n";
651  return false;
652  }
653 
654  std::pair<std::string, YAML::Node> & configPair = fConfigurations.at(configurationIndex);
655 
656  WriteValue(configPair.second, propertyName, property);
657  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Final Node:\n" << configPair.second << "\n";
658 
659  return true;
660 }
661 
669 template<typename T>
670 void AliYAMLConfiguration::WriteValue(YAML::Node & node, std::string propertyName, T & property)
671 {
672  // Find the node name we are interested in
673  // Derived from: https://stackoverflow.com/a/14266139
674  const std::string delimiter = ":";
675  size_t delimiterPosition = 0;
676  std::string tempPropertyName = propertyName;
677 
678  if ((delimiterPosition = tempPropertyName.find(delimiter)) != std::string::npos)
679  {
680  std::string nodeName = tempPropertyName.substr(0, delimiterPosition);
681  tempPropertyName.erase(0, delimiterPosition + delimiter.length());
682  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "nodeName: " << nodeName << "\n";
683  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Node Before:\n" << node << "\n";
684  if (node[nodeName].IsDefined()) {
685  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Using existing node\n";
686  YAML::Node tempNode = node[nodeName];
687  WriteValue(tempNode, tempPropertyName, property);
688  }
689  else {
690  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Creating new node\n";
691  YAML::Node tempNode;
692  node[nodeName] = tempNode;
693  WriteValue(tempNode, tempPropertyName, property);
694  }
695  AliDebugGeneralStream("AliYAMLConfiguration", 2) << "Node After:\n" << node << "\n";
696  }
697  else {
698  // We have finished the recursion. Now we need to save the actual property.
699  node[propertyName] = property;
700  }
701 }
702 
703 #endif
704 
714 template<typename T>
715 unsigned int AliYAMLConfiguration::GetConfigurationIndexFromName(const std::string & name, const std::vector<std::pair<std::string, T>> & configurations) const
716 {
717  int index = -1;
718  for (const auto & configPair : configurations)
719  {
720  if (configPair.first == name) {
721  // Retrieve index
722  // See: https://stackoverflow.com/a/10962459
723  index = std::addressof(configPair) - std::addressof(configurations[0]);
724  break;
725  }
726  }
727 
728  return index;
729 }
730 
731 } // namespace Tools
732 } // namespace PWG
733 
734 #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
Range(It b, It e)
It begin() 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.
Range< It > reverse(ORange &&originalRange)
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
It end() const
std::pair< std::string, YAML::Node > & GetConfiguration(const std::string &name)