9 #include <analysis/VariableManager/Manager.h>
10 #include <analysis/dataobjects/Particle.h>
12 #include <framework/logging/Logger.h>
13 #include <framework/utilities/Conversion.h>
14 #include <framework/utilities/GeneralCut.h>
16 #include <boost/algorithm/string.hpp>
24 Variable::Manager::~Manager() =
default;
32 const std::vector<std::string>& functionArguments)
35 std::string fullname = functionName +
"(" + boost::algorithm::join(functionArguments,
", ") +
")";
39 std::set<std::string> aliasesSeen;
40 for (
auto aliasIter = m_alias.find(fullname); aliasIter != m_alias.end(); aliasIter = m_alias.find(fullname)) {
41 const auto [it, added] = aliasesSeen.insert(fullname);
43 B2FATAL(
"Encountered a loop in the alias definitions between the aliases "
44 << boost::algorithm::join(aliasesSeen,
", "));
46 fullname = aliasIter->second;
48 auto mapIter = m_variables.find(fullname);
49 if (mapIter == m_variables.end()) {
50 if (!createVariable(fullname, functionName, functionArguments))
return nullptr;
51 mapIter = m_variables.find(fullname);
52 if (mapIter == m_variables.end())
return nullptr;
54 return mapIter->second.get();
61 std::set<std::string> aliasesSeen;
62 for (
auto aliasIter = m_alias.find(name); aliasIter != m_alias.end(); aliasIter = m_alias.find(name)) {
63 const auto [it, added] = aliasesSeen.insert(name);
65 B2FATAL(
"Encountered a loop in the alias definitions between the aliases "
66 << boost::algorithm::join(aliasesSeen,
", "));
68 name = aliasIter->second;
70 auto mapIter = m_variables.find(name);
71 if (mapIter == m_variables.end()) {
72 if (!createVariable(name))
return nullptr;
73 mapIter = m_variables.find(name);
74 if (mapIter == m_variables.end())
return nullptr;
76 return mapIter->second.get();
82 std::vector<const Variable::Manager::Var*> variable_pointers;
83 for (
auto& variable : variables) {
84 const Var* x = getVariable(variable);
86 B2WARNING(
"Couldn't find variable " << variable <<
" via the Variable::Manager. Check the name!");
88 variable_pointers.push_back(x);
90 return variable_pointers;
98 assertValidName(alias);
100 if (m_alias.find(alias) != m_alias.end()) {
101 if (variable == m_alias[alias]) {
return true; }
102 B2WARNING(
"An alias with the name '" << alias <<
"' exists and is set to '" << m_alias[alias] <<
"', setting it to '" << variable <<
103 "'. Be aware: only the last alias defined before processing the events will be used!");
104 m_alias[alias] = variable;
108 if (m_variables.find(alias) != m_variables.end()) {
109 B2ERROR(
"Variable with the name '" << alias <<
"' exists already, cannot add it as an alias!");
113 m_alias.insert(std::make_pair(alias, variable));
124 long unsigned int longest_alias_size = 0;
125 for (
const auto& a : m_alias) {
126 if (a.first.length() > longest_alias_size) {
127 longest_alias_size = a.first.length();
130 B2INFO(
"=====================================");
131 B2INFO(
"The following aliases are registered:");
132 for (
const auto& a : m_alias) {
133 B2INFO(std::string(a.first, 0, longest_alias_size) << std::string(longest_alias_size - a.first.length(),
134 ' ') <<
" --> " << a.second);
136 B2INFO(
"=====================================");
142 assertValidName(collection);
144 if (m_collection.find(collection) != m_collection.end()) {
145 B2WARNING(
"Another collection with the name'" << collection <<
"' is already set! I overwrite it!");
146 m_collection[collection] = variables;
150 if (m_variables.find(collection) != m_variables.end()) {
151 B2ERROR(
"Variable with the name '" << collection <<
"' exists already, won't add it as an collection!");
155 m_collection.insert(std::make_pair(collection, variables));
163 return m_collection[collection];
170 std::vector<std::string> temp;
172 for (
const auto& var : variables) {
173 auto it = m_collection.find(var);
174 if (it != m_collection.end()) {
175 temp.insert(temp.end(), it->second.begin(), it->second.end());
187 const static std::regex allowedNameRegex(
"^[a-zA-Z0-9_]*$");
189 if (!std::regex_match(name, allowedNameRegex)) {
190 B2FATAL(
"Variable '" << name <<
191 "' contains forbidden characters! Only alphanumeric characters plus underscores (_) are allowed for variable names.");
198 m_currentGroup = groupName;
203 std::match_results<std::string::const_iterator> results;
206 if (std::regex_match(name, results, std::regex(
"^([0-9]+\\.?[0-9]*)$"))) {
207 float float_number = std::stof(results[1]);
208 auto func = [float_number](
const Particle*) ->
double {
211 m_variables[name] = std::make_shared<Var>(name, func, std::string(
"Returns number ") + name);
216 if (std::regex_match(name, results, std::regex(
"^([a-zA-Z0-9_]*)\\((.*)\\)$"))) {
218 std::string functionName = results[1];
219 boost::algorithm::trim(functionName);
221 for (
auto& str : functionArguments) {
222 boost::algorithm::trim(str);
226 auto parameterIter = m_parameter_variables.find(functionName);
227 if (parameterIter != m_parameter_variables.end()) {
229 std::vector<double> arguments;
230 for (
auto& arg : functionArguments) {
232 number = Belle2::convertString<double>(arg);
233 arguments.push_back(number);
235 auto pfunc = parameterIter->second->function;
236 auto func = [pfunc, arguments](
const Particle * particle) ->
VarVariant {
return pfunc(particle, arguments); };
237 m_variables[name] = std::make_shared<Var>(name, func, parameterIter->second->description, parameterIter->second->group,
238 parameterIter->second->variabletype);
244 auto metaIter = m_meta_variables.find(functionName);
245 if (metaIter != m_meta_variables.end()) {
246 auto func = metaIter->second->function(functionArguments);
247 m_variables[name] = std::make_shared<Var>(name, func, metaIter->second->description, metaIter->second->group,
248 metaIter->second->variabletype);
253 if (not std::regex_match(name, std::regex(
"^[a-zA-Z_][a-zA-Z_0-9]*$")) and not name.empty()) {
257 py::object b2parser_namespace = py::import(
"b2parser");
259 py::tuple expression_tuple = py::extract<boost::python::tuple>(b2parser_namespace.attr(
"parse_expression")(name));
262 std::shared_ptr<const AbstractExpressionNode<Belle2::Variable::Manager>> expression_node =
263 NodeFactory::compile_expression_node<Belle2::Variable::Manager>(expression_tuple);
266 return expression_node->evaluate(
object);
269 m_variables[name] = std::make_shared<Var>(name, func, std::string(
"Returns expression ") + name);
271 }
catch (std::runtime_error& exception) {
272 B2FATAL(
"Encountered bad variable name '" << name <<
"'. Maybe you misspelled it?");
274 }
catch (py::error_already_set&) {
276 B2FATAL(
"Parsing error for formula: '" << name <<
"'");
280 B2FATAL(
"Encountered bad variable name '" << name <<
"'. Maybe you misspelled it?");
285 const std::vector<std::string>& functionArguments)
288 auto parameterIter = m_parameter_variables.find(functionName);
289 if (parameterIter != m_parameter_variables.end()) {
291 std::vector<double> arguments;
292 for (
auto& arg : functionArguments) {
294 number = Belle2::convertString<double>(arg);
295 arguments.push_back(number);
297 auto pfunc = parameterIter->second->function;
298 auto func = [pfunc, arguments](
const Particle * particle) -> std::variant<double, int, bool> {
return pfunc(particle, arguments); };
299 m_variables[fullname] = std::make_shared<Var>(fullname, func, parameterIter->second->description, parameterIter->second->group,
300 parameterIter->second->variabletype);
306 auto metaIter = m_meta_variables.find(functionName);
307 if (metaIter != m_meta_variables.end()) {
308 auto func = metaIter->second->function(functionArguments);
309 m_variables[fullname] = std::make_shared<Var>(fullname, func, metaIter->second->description, metaIter->second->group,
310 metaIter->second->variabletype);
314 B2FATAL(
"Encountered bad variable name '" << fullname <<
"'. Maybe you misspelled it?");
321 const std::string& unit)
324 B2FATAL(
"No function provided for variable '" << name <<
"'.");
327 assertValidName(name);
329 auto mapIter = m_variables.find(name);
330 if (mapIter == m_variables.end()) {
332 auto var = std::make_shared<Var>(name, f, description, m_currentGroup, variabletype);
333 B2DEBUG(19,
"Registered Variable " << name);
334 m_variables[name] = var;
335 m_variablesInRegistrationOrder.push_back(var.get());
337 var.get()->extendDescriptionString(
"\n\n :Unit: " + unit);
340 B2FATAL(
"A variable named '" << name <<
"' was already registered! Note that all variables need a unique name!");
346 const std::string& unit)
349 B2FATAL(
"No function provided for variable '" << name <<
"'.");
352 auto mapIter = m_parameter_variables.find(name);
353 if (mapIter == m_parameter_variables.end()) {
354 auto var = std::make_shared<ParameterVar>(name, f, description, m_currentGroup, variabletype);
355 std::string rawName = name.substr(0, name.find(
'('));
356 assertValidName(rawName);
357 B2DEBUG(19,
"Registered parameter Variable " << rawName);
358 m_parameter_variables[rawName] = var;
359 m_variablesInRegistrationOrder.push_back(var.get());
361 var.get()->extendDescriptionString(
"\n\n :Unit: " + unit);
364 B2FATAL(
"A variable named '" << name <<
"' was already registered! Note that all variables need a unique name!");
372 B2FATAL(
"No function provided for variable '" << name <<
"'.");
375 auto mapIter = m_meta_variables.find(name);
376 if (mapIter == m_meta_variables.end()) {
377 auto var = std::make_shared<MetaVar>(name, f, description, m_currentGroup, variabletype);
378 std::string rawName = name.substr(0, name.find(
'('));
379 assertValidName(rawName);
380 B2DEBUG(19,
"Registered meta Variable " << rawName);
381 m_meta_variables[rawName] = var;
382 m_variablesInRegistrationOrder.push_back(var.get());
384 B2FATAL(
"A variable named '" << name <<
"' was already registered! Note that all variables need a unique name!");
389 const std::string& description)
391 auto varIter = m_deprecated.find(name);
392 if (varIter == m_deprecated.end())
393 m_deprecated.insert(std::make_pair(name, std::make_pair(make_fatal, description)));
395 B2FATAL(
"There seem to be two calls to deprecate the variable: Please remove one.");
397 auto mapIter = m_variables.find(name);
398 if (mapIter != m_variables.end()) {
400 mapIter->second.get()->extendDescriptionString(
"\n\n.. warning:: ");
402 mapIter->second.get()->extendDescriptionString(
"\n\n.. note:: ");
404 mapIter->second.get()->extendDescriptionString(
".. deprecated:: " + version +
"\n " + description);
406 auto parMapIter = m_parameter_variables.find(name);
407 if (parMapIter != m_parameter_variables.end()) {
409 parMapIter->second.get()->extendDescriptionString(
"\n\n.. warning:: ");
411 parMapIter->second.get()->extendDescriptionString(
"\n\n.. note:: ");
413 parMapIter->second.get()->extendDescriptionString(
".. deprecated:: " + version +
"\n " + description);
415 auto metaMapIter = m_meta_variables.find(name);
416 if (metaMapIter != m_meta_variables.end()) {
418 metaMapIter->second.get()->extendDescriptionString(
"\n\n.. warning:: ");
420 metaMapIter->second.get()->extendDescriptionString(
"\n\n.. note:: ");
422 metaMapIter->second.get()->extendDescriptionString(
".. deprecated:: " + version +
"\n " + description);
424 B2FATAL(
"The variable '" << name <<
"' is not registered so it makes no sense to try to deprecate it.");
433 auto varIter = m_deprecated.find(name);
435 if (varIter == m_deprecated.end())
438 bool make_fatal = varIter->second.first;
439 std::string message = varIter->second.second;
441 B2FATAL(
"Variable " << name <<
" is deprecated. " << message);
443 B2WARNING(
"Variable " << name <<
" is deprecated. " << message);
450 std::vector<std::string> names;
451 for (
const VarBase* var : m_variablesInRegistrationOrder) {
452 names.push_back(var->name);
459 std::vector<std::string> names;
460 for (
auto al : m_alias) names.push_back(al.first);
466 const Var* var = getVariable(varName);
468 throw std::runtime_error(
"Variable::Manager::evaluate(): variable '" + varName +
"' not found!");
471 if (var->variabletype == Variable::Manager::VariableDataType::c_double)
472 return std::get<double>(var->function(p));
473 else if (var->variabletype == Variable::Manager::VariableDataType::c_int)
474 return (
double)std::get<int>(var->function(p));
475 else if (var->variabletype == Variable::Manager::VariableDataType::c_bool)
476 return (
double)std::get<bool>(var->function(p));
477 else return std::numeric_limits<double>::quiet_NaN();
Class to store reconstructed particles.
Global list of available variables.
std::vector< std::string > getAliasNames() const
Return a list of all variable alias names (in reverse order added).
std::function< VarVariant(const Particle *)> FunctionPtr
functions stored take a const Particle* and return VarVariant.
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...
const Var * getVariable(std::string name)
Get the variable belonging to the given key.
std::variant< double, int, bool > VarVariant
NOTE: the python interface is documented manually in analysis/doc/Variables.rst (because we use ROOT ...
void deprecateVariable(const std::string &name, bool make_fatal, const std::string &version, const std::string &description)
Make a variable deprecated.
std::vector< const Belle2::Variable::Manager::VarBase * > getVariables() const
Return list of all variables (in order registered).
static Manager & Instance()
get singleton instance.
void printAliases()
Print existing aliases.
bool createVariable(const std::string &name)
Creates and registers a concrete variable (Var) from a MetaVar, ParameterVar or numeric constant.
void assertValidName(const std::string &name)
Abort with B2FATAL if name is not a valid name for a variable.
void clearAliases()
Clear existing aliases.
std::function< FunctionPtr(const std::vector< std::string > &)> MetaFunctionPtr
meta functions stored take a const std::vector<std::string>& and return a FunctionPtr.
std::vector< std::string > getNames() const
Return list of all variable names (in order registered).
void setVariableGroup(const std::string &groupName)
All variables registered after VARIABLE_GROUP(groupName) will be added to this group.
std::vector< std::string > getCollection(const std::string &collection)
Get Collection Returns variable names corresponding to the given collection.
bool addAlias(const std::string &alias, const std::string &variable)
Add alias Return true if the alias was successfully added.
bool addCollection(const std::string &collection, const std::vector< std::string > &variables)
Add collection Return true if the collection was successfully added.
std::function< VarVariant(const Particle *, const std::vector< double > &)> ParameterFunctionPtr
parameter functions stored take a const Particle*, const std::vector<double>& and return VarVariant.
VariableDataType
data type of variables
void registerVariable(const std::string &name, const Manager::FunctionPtr &f, const std::string &description, const Manager::VariableDataType &v, const std::string &unit="")
Register a variable.
void checkDeprecatedVariable(const std::string &name)
Check if a variable is deprecated.
double evaluate(const std::string &varName, const Particle *p)
evaluate variable 'varName' on given Particle.
std::vector< std::string > splitOnDelimiterAndConserveParenthesis(std::string str, char delimiter, char open, char close)
Split into std::vector on delimiter ignoring delimiters between parenthesis.
Abstract base class for different kinds of events.
Base class for information common to all types of variables.
A variable returning a floating-point value for a given Particle.