9#include <analysis/VariableManager/Manager.h> 
   10#include <analysis/dataobjects/Particle.h> 
   11#include <analysis/dataobjects/ParticleList.h> 
   13#include <framework/logging/Logger.h> 
   14#include <framework/utilities/Conversion.h> 
   15#include <framework/utilities/GeneralCut.h> 
   17#include <boost/algorithm/string.hpp> 
   25Variable::Manager::~Manager() = 
default;
 
   33    const std::vector<std::string>& functionArguments)
 
   36  std::string fullname = functionName + 
"(" + boost::algorithm::join(functionArguments, 
", ") + 
")";
 
   40  std::set<std::string> aliasesSeen;
 
   41  for (
auto aliasIter = 
m_alias.find(fullname); aliasIter != 
m_alias.end(); aliasIter = 
m_alias.find(fullname)) {
 
   42    const auto [it, added] = aliasesSeen.insert(fullname);
 
   44      B2FATAL(
"Encountered a loop in the alias definitions between the aliases " 
   45              << boost::algorithm::join(aliasesSeen, 
", "));
 
   47    fullname = aliasIter->second;
 
   51    if (!
createVariable(fullname, functionName, functionArguments)) 
return nullptr;
 
   55  return mapIter->second.get();
 
 
   62  std::set<std::string> aliasesSeen;
 
   63  for (
auto aliasIter = 
m_alias.find(name); aliasIter != 
m_alias.end(); aliasIter = 
m_alias.find(name)) {
 
   64    const auto [it, added] = aliasesSeen.insert(name);
 
   66      B2FATAL(
"Encountered a loop in the alias definitions between the aliases " 
   67              << boost::algorithm::join(aliasesSeen, 
", "));
 
   69    name = aliasIter->second;
 
   77  return mapIter->second.get();
 
 
   83  std::vector<const Variable::Manager::Var*> variable_pointers;
 
   84  for (
auto& variable : variables) {
 
   87      B2WARNING(
"Couldn't find variable " << variable << 
" via the Variable::Manager. Check the name!");
 
   89    variable_pointers.push_back(x);
 
   91  return variable_pointers;
 
 
  102    if (variable == 
m_alias[alias]) { 
return true; }
 
  103    B2WARNING(
"An alias with the name '" << alias << 
"' exists and is set to '" << 
m_alias[alias] << 
"', setting it to '" << variable <<
 
  104              "'. Be aware: only the last alias defined before processing the events will be used!");
 
  110    B2ERROR(
"Variable with the name '" << alias << 
"' exists already, cannot add it as an alias!");
 
  114  m_alias.insert(std::make_pair(alias, variable));
 
 
  125  long unsigned int longest_alias_size = 0;
 
  126  for (
const auto& a : 
m_alias) {
 
  127    if (a.first.length() > longest_alias_size) {
 
  128      longest_alias_size = a.first.length();
 
  131  B2INFO(
"=====================================");
 
  132  B2INFO(
"The following aliases are registered:");
 
  133  for (
const auto& a : 
m_alias) {
 
  134    B2INFO(std::string(a.first, 0, longest_alias_size) << std::string(longest_alias_size - a.first.length(),
 
  135           ' ') << 
" --> " << a.second);
 
  137  B2INFO(
"=====================================");
 
 
  158    B2WARNING(
"Another collection with the name'" << collection << 
"' is already set! I overwrite it!");
 
  164    B2ERROR(
"Variable with the name '" << collection << 
"' exists already, won't add it as an collection!");
 
  168  m_collection.insert(std::make_pair(collection, variables));
 
 
  183  std::vector<std::string> temp;
 
  185  for (
const auto& var : variables) {
 
  188      temp.insert(temp.end(), it->second.begin(), it->second.end());
 
 
  200  const static std::regex allowedNameRegex(
"^[a-zA-Z0-9_]*$");
 
  202  if (!std::regex_match(name, allowedNameRegex)) {
 
  203    B2FATAL(
"Variable '" << name <<
 
  204            "' contains forbidden characters! Only alphanumeric characters plus underscores (_) are allowed for variable names.");
 
 
  216  std::match_results<std::string::const_iterator> results;
 
  219  if (std::regex_match(name, results, std::regex(
"^([0-9]+\\.?[0-9]*)$"))) {
 
  220    float float_number = std::stof(results[1]);
 
  221    auto func = [float_number](
const Particle*) -> 
double {
 
  224    m_variables[name] = std::make_shared<Var>(name, func, std::string(
"Returns number ") + name);
 
  229  if (std::regex_match(name, results, std::regex(
"^([a-zA-Z0-9_]*)\\((.*)\\)$"))) {
 
  231    std::string functionName = results[1];
 
  232    boost::algorithm::trim(functionName);
 
  234    for (
auto& str : functionArguments) {
 
  235      boost::algorithm::trim(str);
 
  242      std::vector<double> arguments;
 
  243      for (
auto& arg : functionArguments) {
 
  246        arguments.push_back(number);
 
  248      auto pfunc = parameterIter->second->function;
 
  249      auto func = [pfunc, arguments](
const Particle * particle) -> 
VarVariant { 
return pfunc(particle, arguments); };
 
  250      m_variables[name] = std::make_shared<Var>(name, func, parameterIter->second->description, parameterIter->second->group,
 
  251                                                parameterIter->second->variabletype);
 
  259      auto func = metaIter->second->function(functionArguments);
 
  260      m_variables[name] = std::make_shared<Var>(name, func, metaIter->second->description, metaIter->second->group,
 
  261                                                metaIter->second->variabletype);
 
  266  if (not std::regex_match(name, std::regex(
"^[a-zA-Z_][a-zA-Z_0-9]*$")) and not name.empty()) {
 
  270      py::object b2parser_namespace = py::import(
"b2parser");
 
  272      py::tuple expression_tuple = py::extract<boost::python::tuple>(b2parser_namespace.attr(
"parse_expression")(name));
 
  275        std::shared_ptr<const AbstractExpressionNode<Belle2::Variable::Manager>> expression_node =
 
  279          return expression_node->evaluate(
object);
 
  282        m_variables[name] = std::make_shared<Var>(name, func, std::string(
"Returns expression ") + name);
 
  284      } 
catch (std::runtime_error& exception) {
 
  285        B2FATAL(
"Encountered bad variable name '" << name << 
"'. Maybe you misspelled it?");
 
  287    } 
catch (py::error_already_set&) {
 
  289      B2FATAL(
"Parsing error for formula: '" << name << 
"'");
 
  293  B2FATAL(
"Encountered bad variable name '" << name << 
"'. Maybe you misspelled it?");
 
 
  298                                       const std::vector<std::string>& functionArguments)
 
  304    std::vector<double> arguments;
 
  305    for (
auto& arg : functionArguments) {
 
  308      arguments.push_back(number);
 
  310    auto pfunc = parameterIter->second->function;
 
  311    auto func = [pfunc, arguments](
const Particle * particle) -> std::variant<double, int, bool> { 
return pfunc(particle, arguments); };
 
  312    m_variables[fullname] = std::make_shared<Var>(fullname, func, parameterIter->second->description, parameterIter->second->group,
 
  313                                                  parameterIter->second->variabletype);
 
  321    auto func = metaIter->second->function(functionArguments);
 
  322    m_variables[fullname] = std::make_shared<Var>(fullname, func, metaIter->second->description, metaIter->second->group,
 
  323                                                  metaIter->second->variabletype);
 
  327  B2FATAL(
"Encountered bad variable name '" << fullname << 
"'. Maybe you misspelled it?");
 
 
  334                                         const std::string& unit)
 
  337    B2FATAL(
"No function provided for variable '" << name << 
"'.");
 
  345    auto var = std::make_shared<Var>(name, f, description, 
m_currentGroup, variabletype);
 
  346    B2DEBUG(19, 
"Registered Variable " << name);
 
  350      var.get()->extendDescriptionString(
":Unit: " + unit);
 
  353    B2FATAL(
"A variable named '" << name << 
"' was already registered! Note that all variables need a unique name!");
 
 
  359                                         const std::string& unit)
 
  362    B2FATAL(
"No function provided for variable '" << name << 
"'.");
 
  367    auto var = std::make_shared<ParameterVar>(name, f, description, 
m_currentGroup, variabletype);
 
  368    std::string rawName = name.substr(0, name.find(
'('));
 
  370    B2DEBUG(19, 
"Registered parameter Variable " << rawName);
 
  374      var.get()->extendDescriptionString(
":Unit: " + unit);
 
  377    B2FATAL(
"A variable named '" << name << 
"' was already registered! Note that all variables need a unique name!");
 
 
  385    B2FATAL(
"No function provided for variable '" << name << 
"'.");
 
  390    auto var = std::make_shared<MetaVar>(name, f, description, 
m_currentGroup, variabletype);
 
  391    std::string rawName = name.substr(0, name.find(
'('));
 
  393    B2DEBUG(19, 
"Registered meta Variable " << rawName);
 
  397    B2FATAL(
"A variable named '" << name << 
"' was already registered! Note that all variables need a unique name!");
 
 
  402                                          const std::string& description)
 
  406    m_deprecated.insert(std::make_pair(name, std::make_pair(make_fatal, description)));
 
  408    B2FATAL(
"There seem to be two calls to deprecate the variable: Please remove one.");
 
  413      mapIter->second.get()->extendDescriptionString(
"\n\n.. warning:: ");
 
  415      mapIter->second.get()->extendDescriptionString(
"\n\n.. note:: ");
 
  417    mapIter->second.get()->extendDescriptionString(
".. deprecated:: " + version + 
"\n " + description);
 
  422        parMapIter->second.get()->extendDescriptionString(
"\n\n.. warning:: ");
 
  424        parMapIter->second.get()->extendDescriptionString(
"\n\n.. note:: ");
 
  426      parMapIter->second.get()->extendDescriptionString(
".. deprecated:: " + version + 
"\n " + description);
 
  431          metaMapIter->second.get()->extendDescriptionString(
"\n\n.. warning:: ");
 
  433          metaMapIter->second.get()->extendDescriptionString(
"\n\n.. note:: ");
 
  435        metaMapIter->second.get()->extendDescriptionString(
".. deprecated:: " + version + 
"\n " + description);
 
  437        B2FATAL(
"The variable '" << name << 
"' is not registered so it makes no sense to try to deprecate it.");
 
 
  451    bool make_fatal = varIter->second.first;
 
  452    std::string message = varIter->second.second;
 
  454      B2FATAL(
"Variable " << name << 
" is deprecated. " << message);
 
  456      B2WARNING(
"Variable " << name << 
" is deprecated. " << message);
 
 
  463  std::vector<std::string> names;
 
  465    names.push_back(var->name);
 
 
  472  std::vector<std::string> names;
 
  473  for (
auto al : 
m_alias) names.push_back(al.first);
 
 
  481    throw std::runtime_error(
"Variable::Manager::evaluate(): variable '" + varName + 
"' not found!");
 
  484  if (var->variabletype == Variable::Manager::VariableDataType::c_double)
 
  485    return std::get<double>(var->function(p));
 
  486  else if (var->variabletype == Variable::Manager::VariableDataType::c_int)
 
  487    return (
double)std::get<int>(var->function(p));
 
  488  else if (var->variabletype == Variable::Manager::VariableDataType::c_bool)
 
  489    return (
double)std::get<bool>(var->function(p));
 
  490  else return std::numeric_limits<double>::quiet_NaN();
 
 
  495  std::vector<double> values;
 
  496  values.reserve(varNames.size() * plist->getListSize());
 
  497  for (
size_t iPart = 0; iPart < plist->getListSize(); ++iPart) {
 
  498    const Particle* p = plist->getParticle(iPart);
 
  499    for (
size_t iVar = 0; iVar < varNames.size(); ++iVar)
 
  500      values.push_back(
evaluate(varNames[iVar], p));
 
 
static std::unique_ptr< const AbstractExpressionNode< AVariableManager > > compile_expression_node(Nodetuple tuple)
This template function creates a ExpressionNode from a boost::python::tuple The Python Parser encodes...
ParticleList is a container class that stores a collection of Particle objects.
Class to store reconstructed particles.
Global list of available variables.
std::vector< const Belle2::Variable::Manager::VarBase * > getVariables() const
Return list of all variables (in order registered).
std::vector< const VarBase * > m_variablesInRegistrationOrder
List of variables in registration order.
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...
std::string m_currentGroup
Group last set via VARIABLE_GROUP().
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 ...
std::map< std::string, std::string > m_alias
List of registered aliases.
std::map< std::string, std::shared_ptr< Var > > m_variables
List of registered variables.
void deprecateVariable(const std::string &name, bool make_fatal, const std::string &version, const std::string &description)
Make a variable deprecated.
std::map< std::string, std::shared_ptr< ParameterVar > > m_parameter_variables
List of registered parameter variables.
static Manager & Instance()
get singleton instance.
void printAliases()
Print existing aliases.
std::map< std::string, std::pair< bool, std::string > > m_deprecated
List of deprecated variables.
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).
std::map< std::string, std::vector< std::string > > m_collection
List of registered collections.
void setVariableGroup(const std::string &groupName)
All variables registered after VARIABLE_GROUP(groupName) will be added to this group.
std::string resolveAlias(const std::string &alias)
Resolve alias Return original variable name.
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< double > evaluateVariables(const std::vector< std::string > &varNames, const ParticleList *plist)
Evaluate each variable in the vector 'varNames' on given ParticleList and return a flattened vector o...
std::map< std::string, std::shared_ptr< MetaVar > > m_meta_variables
List of registered meta variables.
T convertString(const std::string &str)
Converts a string to type T (one of float, double, long double, int, long int, unsigned long int).
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.