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.