Belle II Software  release-05-02-19
Manager.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2013-2019 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Thomas Keck, Christian Pulvermacher *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #include <analysis/VariableManager/Manager.h>
12 #include <analysis/dataobjects/Particle.h>
13 
14 #include <framework/logging/Logger.h>
15 #include <framework/utilities/Conversion.h>
16 #include <framework/utilities/GeneralCut.h>
17 
18 #include <boost/algorithm/string.hpp>
19 
20 #include <string>
21 #include <regex>
22 #include <set>
23 
24 using namespace Belle2;
25 
26 Variable::Manager::~Manager() = default;
28 {
29  static Variable::Manager v;
30  return v;
31 }
32 
34 {
35  // resolve aliases. Aliases might point to other aliases so we need to keep a
36  // set of what we have seen so far to avoid running into infinite loops
37  std::set<std::string> aliasesSeen;
38  for (auto aliasIter = m_alias.find(name); aliasIter != m_alias.end(); aliasIter = m_alias.find(name)) {
39  const auto [it, added] = aliasesSeen.insert(name);
40  if (!added) {
41  B2FATAL("Encountered a loop in the alias definitions between the aliases "
42  << boost::algorithm::join(aliasesSeen, ", "));
43  }
44  name = aliasIter->second;
45  }
46  auto mapIter = m_variables.find(name);
47  if (mapIter == m_variables.end()) {
48  if (!createVariable(name)) return nullptr;
49  mapIter = m_variables.find(name);
50  if (mapIter == m_variables.end()) return nullptr;
51  }
52  return mapIter->second.get();
53 }
54 
55 std::vector<const Variable::Manager::Var*> Variable::Manager::getVariables(const std::vector<std::string>& variables)
56 {
57 
58  std::vector<const Variable::Manager::Var*> variable_pointers;
59  for (auto& variable : variables) {
60  const Var* x = getVariable(variable);
61  if (x == nullptr) {
62  B2WARNING("Couldn't find variable " << variable << " via the Variable::Manager. Check the name!");
63  }
64  variable_pointers.push_back(x);
65  }
66  return variable_pointers;
67 
68 }
69 
70 
71 bool Variable::Manager::addAlias(const std::string& alias, const std::string& variable)
72 {
73 
74  assertValidName(alias);
75 
76  if (m_alias.find(alias) != m_alias.end()) {
77  if (variable == m_alias[alias]) { return true; }
78  B2WARNING("An alias with the name '" << alias << "' exists and is set to '" << m_alias[alias] << "', setting it to '" << variable <<
79  "'. Be aware: only the last alias defined before processing the events will be used!");
80  m_alias[alias] = variable;
81  return true;
82  }
83 
84  if (m_variables.find(alias) != m_variables.end()) {
85  B2ERROR("Variable with the name '" << alias << "' exists already, cannot add it as an alias!");
86  return false;
87  }
88 
89  m_alias.insert(std::make_pair(alias, variable));
90  return true;
91 }
92 
93 
95 {
96  long unsigned int longest_alias_size = 0;
97  for (const auto& a : m_alias) {
98  if (a.first.length() > longest_alias_size) {
99  longest_alias_size = a.first.length();
100  }
101  }
102  B2INFO("=====================================");
103  B2INFO("The following aliases are registered:");
104  for (const auto& a : m_alias) {
105  B2INFO(std::string(a.first, 0, longest_alias_size) << std::string(longest_alias_size - a.first.length(),
106  ' ') << " --> " << a.second);
107  }
108  B2INFO("=====================================");
109 }
110 
111 bool Variable::Manager::addCollection(const std::string& collection, const std::vector<std::string>& variables)
112 {
113 
114  assertValidName(collection);
115 
116  if (m_collection.find(collection) != m_collection.end()) {
117  B2WARNING("Another collection with the name'" << collection << "' is already set! I overwrite it!");
118  m_collection[collection] = variables;
119  return true;
120  }
121 
122  if (m_variables.find(collection) != m_variables.end()) {
123  B2ERROR("Variable with the name '" << collection << "' exists already, won't add it as an collection!");
124  return false;
125  }
126 
127  m_collection.insert(std::make_pair(collection, variables));
128  return true;
129 }
130 
131 
132 std::vector<std::string> Variable::Manager::getCollection(const std::string& collection)
133 {
134 
135  return m_collection[collection];
136 
137 }
138 
139 std::vector<std::string> Variable::Manager::resolveCollections(const std::vector<std::string>& variables)
140 {
141 
142  std::vector<std::string> temp;
143 
144  for (const auto& var : variables) {
145  auto it = m_collection.find(var);
146  if (it != m_collection.end()) {
147  temp.insert(temp.end(), it->second.begin(), it->second.end());
148  } else {
149  temp.push_back(var);
150  }
151  }
152  return temp;
153 
154 }
155 
156 
157 void Variable::Manager::assertValidName(const std::string& name)
158 {
159  const static std::regex allowedNameRegex("^[a-zA-Z0-9_]*$");
160 
161  if (!std::regex_match(name, allowedNameRegex)) {
162  B2FATAL("Variable '" << name <<
163  "' contains forbidden characters! Only alphanumeric characters plus underscores (_) are allowed for variable names.");
164  }
165 }
166 
167 
168 void Variable::Manager::setVariableGroup(const std::string& groupName)
169 {
170  m_currentGroup = groupName;
171 }
172 
173 bool Variable::Manager::createVariable(const std::string& name)
174 {
175  std::match_results<std::string::const_iterator> results;
176 
177  // Check if name is a simple number
178  if (std::regex_match(name, results, std::regex("^([0-9]+\\.?[0-9]*)$"))) {
179  float float_number = std::stof(results[1]);
180  auto func = [float_number](const Particle*) -> double {
181  return float_number;
182  };
183  m_variables[name] = std::make_shared<Var>(name, func, std::string("Returns number ") + name);
184  return true;
185  }
186 
187  // Check if name is a function call
188  if (std::regex_match(name, results, std::regex("^([a-zA-Z0-9_]*)\\((.*)\\)$"))) {
189 
190  std::string functionName = results[1];
191  boost::algorithm::trim(functionName);
192  std::vector<std::string> functionArguments = splitOnDelimiterAndConserveParenthesis(results[2], ',', '(', ')');
193  for (auto& str : functionArguments) {
194  boost::algorithm::trim(str);
195  }
196 
197  // Search function name in parameter variables
198  auto parameterIter = m_parameter_variables.find(functionName);
199  if (parameterIter != m_parameter_variables.end()) {
200 
201  std::vector<double> arguments;
202  for (auto& arg : functionArguments) {
203  double number = 0;
204  number = Belle2::convertString<double>(arg);
205  arguments.push_back(number);
206  }
207  auto pfunc = parameterIter->second->function;
208  auto func = [pfunc, arguments](const Particle * particle) -> double { return pfunc(particle, arguments); };
209  m_variables[name] = std::make_shared<Var>(name, func, parameterIter->second->description, parameterIter->second->group);
210  return true;
211 
212  }
213 
214  // Search function name in meta variables
215  auto metaIter = m_meta_variables.find(functionName);
216  if (metaIter != m_meta_variables.end()) {
217  auto func = metaIter->second->function(functionArguments);
218  m_variables[name] = std::make_shared<Var>(name, func, metaIter->second->description, metaIter->second->group);
219  return true;
220  }
221  }
222 
223  B2FATAL("Encountered bad variable name '" << name << "'. Maybe you misspelled it?");
224  return false;
225 }
226 
227 
229  const std::string& description)
230 {
231  if (!f) {
232  B2FATAL("No function provided for variable '" << name << "'.");
233  }
234 
235  assertValidName(name);
236 
237  auto mapIter = m_variables.find(name);
238  if (mapIter == m_variables.end()) {
239  auto var = std::make_shared<Var>(name, f, description, m_currentGroup);
240  B2DEBUG(19, "Registered Variable " << name);
241  m_variables[name] = var;
242  m_variablesInRegistrationOrder.push_back(var.get());
243  } else {
244  B2FATAL("A variable named '" << name << "' was already registered! Note that all variables need a unique name!");
245  }
246 }
247 
249  const std::string& description)
250 {
251  if (!f) {
252  B2FATAL("No function provided for variable '" << name << "'.");
253  }
254 
255  auto mapIter = m_parameter_variables.find(name);
256  if (mapIter == m_parameter_variables.end()) {
257  auto var = std::make_shared<ParameterVar>(name, f, description, m_currentGroup);
258  std::string rawName = name.substr(0, name.find('('));
259  assertValidName(rawName);
260  B2DEBUG(19, "Registered parameter Variable " << rawName);
261  m_parameter_variables[rawName] = var;
262  m_variablesInRegistrationOrder.push_back(var.get());
263  } else {
264  B2FATAL("A variable named '" << name << "' was already registered! Note that all variables need a unique name!");
265  }
266 }
267 
269  const std::string& description)
270 {
271  if (!f) {
272  B2FATAL("No function provided for variable '" << name << "'.");
273  }
274 
275  auto mapIter = m_meta_variables.find(name);
276  if (mapIter == m_meta_variables.end()) {
277  auto var = std::make_shared<MetaVar>(name, f, description, m_currentGroup);
278  std::string rawName = name.substr(0, name.find('('));
279  assertValidName(rawName);
280  B2DEBUG(19, "Registered meta Variable " << rawName);
281  m_meta_variables[rawName] = var;
282  m_variablesInRegistrationOrder.push_back(var.get());
283  } else {
284  B2FATAL("A variable named '" << name << "' was already registered! Note that all variables need a unique name!");
285  }
286 }
287 
288 
289 std::vector<std::string> Variable::Manager::getNames() const
290 {
291  std::vector<std::string> names;
292  for (const VarBase* var : m_variablesInRegistrationOrder) {
293  names.push_back(var->name);
294  }
295  return names;
296 }
297 
298 std::vector<std::string> Variable::Manager::getAliasNames() const
299 {
300  std::vector<std::string> names;
301  for (auto al : m_alias) names.push_back(al.first);
302  return names;
303 }
304 
305 double Variable::Manager::evaluate(const std::string& varName, const Particle* p)
306 {
307  const Var* var = getVariable(varName);
308  if (!var) {
309  throw std::runtime_error("Variable::Manager::evaluate(): variable '" + varName + "' not found!");
310  return 0.0; //never reached, suppresses cppcheck warning
311  }
312 
313  return var->function(p);
314 }
Belle2::Variable::Manager::registerVariable
void registerVariable(const std::string &name, const Manager::FunctionPtr &f, const std::string &description)
Register a variable.
Definition: Manager.cc:228
Belle2::Variable::Manager::Var
A variable returning a floating-point value for a given Particle.
Definition: Manager.h:137
Belle2::Variable::Manager::createVariable
bool createVariable(const std::string &name)
Creates and registers a concrete variable (Var) from a MetaVar, ParameterVar or numeric constant.
Definition: Manager.cc:173
Belle2::Variable::Manager::getNames
std::vector< std::string > getNames() const
Return list of all variable names (in order registered).
Definition: Manager.cc:289
Belle2::splitOnDelimiterAndConserveParenthesis
std::vector< std::string > splitOnDelimiterAndConserveParenthesis(std::string str, char delimiter, char open, char close)
Split into std::vector on delimiter ignoring delimiters between parenthesis.
Definition: GeneralCut.cc:72
Belle2::Variable::Manager::getVariable
const Var * getVariable(std::string name)
Get the variable belonging to the given key.
Definition: Manager.cc:33
Belle2::Variable::Manager::getVariables
std::vector< const Belle2::Variable::Manager::VarBase * > getVariables() const
Return list of all variables (in order registered).
Definition: Manager.h:200
Belle2::Variable::Manager::addAlias
bool addAlias(const std::string &alias, const std::string &variable)
Add alias Return true if the alias was successfully added.
Definition: Manager.cc:71
Belle2::Variable::Manager::printAliases
void printAliases()
Print existing aliases.
Definition: Manager.cc:94
Belle2::Variable::Manager::evaluate
double evaluate(const std::string &varName, const Particle *p)
evaluate variable 'varName' on given Particle.
Definition: Manager.cc:305
Belle2::Variable::Manager::ParameterFunctionPtr
std::function< double(const Particle *, const std::vector< double > &)> ParameterFunctionPtr
parameter functions stored take a const Particle*, const std::vector<double>& and return double.
Definition: Manager.h:120
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::Variable::Manager::FunctionPtr
std::function< double(const Particle *)> FunctionPtr
NOTE: the python interface is documented manually in analysis/doc/Variables.rst (because we use ROOT ...
Definition: Manager.h:118
Belle2::Variable::Manager::addCollection
bool addCollection(const std::string &collection, const std::vector< std::string > &variables)
Add collection Return true if the collection was successfully added.
Definition: Manager.cc:111
Belle2::Variable::Manager::setVariableGroup
void setVariableGroup(const std::string &groupName)
All variables registered after VARIABLE_GROUP(groupName) will be added to this group.
Definition: Manager.cc:168
Belle2::Variable::Manager::MetaFunctionPtr
std::function< FunctionPtr(const std::vector< std::string > &)> MetaFunctionPtr
meta functions stored take a const std::vector<std::string>& and return a FunctionPtr.
Definition: Manager.h:122
Belle2::Variable::Manager::getAliasNames
std::vector< std::string > getAliasNames() const
Return a list of all variable alias names (in reverse order added).
Definition: Manager.cc:298
Belle2::Variable::Manager::resolveCollections
std::vector< std::string > resolveCollections(const std::vector< std::string > &variables)
Resolve Collection Returns variable names corresponding to the given collection or if it is not a col...
Definition: Manager.cc:139
Belle2::Particle
Class to store reconstructed particles.
Definition: Particle.h:77
Belle2::Variable::Manager::VarBase
Base class for information common to all types of variables.
Definition: Manager.h:127
Belle2::Variable::Manager::assertValidName
void assertValidName(const std::string &name)
Abort with B2FATAL if name is not a valid name for a variable.
Definition: Manager.cc:157
Belle2::Variable::Manager::getCollection
std::vector< std::string > getCollection(const std::string &collection)
Get Collection Returns variable names corresponding to the given collection.
Definition: Manager.cc:132
Belle2::Variable::Manager
Global list of available variables.
Definition: Manager.h:108
Belle2::Variable::Manager::Instance
static Manager & Instance()
get singleton instance.
Definition: Manager.cc:27