Belle II Software  release-08-01-10
variableManager.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 #include <analysis/VariableManager/Manager.h>
9 #include <analysis/VariableManager/Utility.h>
10 #include <analysis/dataobjects/Particle.h>
11 #include <framework/utilities/TestHelpers.h>
12 
13 #include <gtest/gtest.h>
14 
15 using namespace std;
16 using namespace Belle2;
17 using namespace Belle2::Variable;
18 namespace {
19 
21  double dummyVar(const Particle*) { return 42.0; }
22  double dummyVarWithParameters(const Particle*, const std::vector<double>& parameters)
23  {
24  double result = 0;
25  for (auto& x : parameters)
26  result += x;
27  return result;
28  }
29  Manager::FunctionPtr dummyMetaVar(const std::vector<std::string>& arguments)
30  {
31  std::string arg = arguments[0];
32  auto func = [arg](const Particle*) -> double {
33  return arg.size();
34  };
35  return func;
36  }
37 
39  TEST(VariableTest, ManagerDeathTest)
40  {
41  //this does not exist
42  EXPECT_B2FATAL(Manager::Instance().getVariable("THISDOESNTEXIST"));
43  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(THISDOESNTEXIST+:THISDOENTEITHER"));
44  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(THISDOESNTEXIST':THISDOENTEITHER"));
45  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(THISDOESNTEXIST-:THISDOENTEITHER"));
46  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(THISDOESNTEXIST&THISDOENTEITHER"));
47  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(THISDOESNTEXIST&"));
48  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(&THISISILLEGAL+1"));
49 
50  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(THISDOESNTEXIST + THISDOENTEITHER"));
51  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(THISDOESNTEXIST+abs(THISDOENTEITHER))"));
52  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(THISDOESNTEXIST + abs( THISDOENTEITHER))"));
53  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(THISDOESNTEXIST * 1)"));
54  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(THISDOESNTEXIST - 2)"));
55  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(THISDOESNTEXIST**3)"));
56  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(THISDOESNTEXIST**abs(p))"));
57  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(THISDOESNTEXIST&**abs(p))"));
58  EXPECT_B2FATAL(Manager::Instance().getVariable("abs(funcdoesnotexist&(p))"));
59 
60  //this exists
61  const Manager::Var* absvar1 = Manager::Instance().getVariable("abs(1+1)");
62  EXPECT_TRUE(absvar1 != nullptr);
63  EXPECT_EQ(std::get<double>(absvar1->function(nullptr)), 2);
64 
65  const Manager::Var* absvar2 = Manager::Instance().getVariable("abs(1/2)");
66  EXPECT_TRUE(absvar2 != nullptr);
67  EXPECT_EQ(std::get<double>(absvar2->function(nullptr)), 0.5);
68 
69  const Manager::Var* absvar3 = Manager::Instance().getVariable("abs(2*10)");
70  EXPECT_TRUE(absvar3 != nullptr);
71  EXPECT_EQ(std::get<double>(absvar3->function(nullptr)), 20);
72 
73  const Manager::Var* absvar4 = Manager::Instance().getVariable("abs(2**10)");
74  EXPECT_TRUE(absvar4 != nullptr);
75  EXPECT_EQ(std::get<double>(absvar4->function(nullptr)), 1024);
76 
77  const Manager::Var* absvar5 = Manager::Instance().getVariable("abs(2^10)");
78  EXPECT_TRUE(absvar5 != nullptr);
79  EXPECT_EQ(std::get<double>(absvar5->function(nullptr)), 1024);
80 
81  const Manager::Var* absvar6 = Manager::Instance().getVariable("abs(10*p)");
82  EXPECT_TRUE(absvar6 != nullptr);
83 
84  const Manager::Var* absvar7 = Manager::Instance().getVariable("abs(10+p)");
85  EXPECT_TRUE(absvar7 != nullptr);
86 
87  const Manager::Var* absvar8 = Manager::Instance().getVariable("abs(10-p)");
88  EXPECT_TRUE(absvar8 != nullptr);
89 
90  const Manager::Var* absvar9 = Manager::Instance().getVariable("abs(10**p)");
91  EXPECT_TRUE(absvar9 != nullptr);
92 
93  const Manager::Var* absvar10 = Manager::Instance().getVariable("abs(10^p)");
94  EXPECT_TRUE(absvar10 != nullptr);
95 
96  const Manager::Var* absvar11 = Manager::Instance().getVariable("abs(10/p)");
97  EXPECT_TRUE(absvar11 != nullptr);
98 
99  const Manager::Var* pvar = Manager::Instance().getVariable("p");
100  EXPECT_TRUE(pvar != nullptr);
101 
102  const Manager::Var* absvar12 = Manager::Instance().getVariable("abs(2+3*2)");
103  EXPECT_TRUE(absvar12 != nullptr);
104  EXPECT_EQ(std::get<double>(absvar12->function(nullptr)), 8);
105 
106  const Manager::Var* absvar13 = Manager::Instance().getVariable("abs(((2+3)*2))");
107  EXPECT_TRUE(absvar13 != nullptr);
108  EXPECT_EQ(std::get<double>(absvar13->function(nullptr)), 10);
109 
110  // Test that nested metavariables with multiple arguments are parsed correctly
111  const Manager::Var* minformulas = Manager::Instance().getVariable("passesCut(min(2+min(1/3, abs(-2/3)), 2+2/3) > 2.3)");
112  EXPECT_TRUE(minformulas != nullptr);
113  EXPECT_TRUE(std::get<bool>(minformulas->function(nullptr)));
114 
115 
116  //test special variable operations
117  const Manager::Var* daughterProductP = Manager::Instance().getVariable("daughterProductOf(p)");
118  EXPECT_TRUE(daughterProductP != nullptr);
119 
120  const Manager::Var* daughterSumP = Manager::Instance().getVariable("daughterSumOf(p)");
121  EXPECT_TRUE(daughterSumP != nullptr);
122 
123  const Manager::Var* daughter1P = Manager::Instance().getVariable("daughter(1, p)");
124  EXPECT_TRUE(daughter1P != nullptr);
125 
126  const Manager::Var* extraInfo = Manager::Instance().getVariable("extraInfo(signalProbability)");
127  EXPECT_TRUE(extraInfo != nullptr);
128 
129  const Manager::Var* nested = Manager::Instance().getVariable("daughterSumOf(daughter(1, extraInfo(signalProbability)))");
130  EXPECT_TRUE(nested != nullptr);
131 
132  EXPECT_B2FATAL(Manager::Instance().getVariable("funcDoesNotExist(p)"));
133 
134  EXPECT_B2FATAL(Manager::Instance().getVariable("daughterSumOf(daughter(1, ExtraInfoWrongName(signalProbability)))"));
135 
136  // Test collection
137  auto vec = Manager::Instance().resolveCollections({"myCollection"});
138  EXPECT_EQ(vec.size(), 1);
139  EXPECT_EQ(vec[0], "myCollection");
140  EXPECT_TRUE(Manager::Instance().addCollection("myCollection", {"p", "px", "py", "pz"}));
141 
142  auto vec2 = Manager::Instance().resolveCollections({"myCollection"});
143  EXPECT_EQ(vec2.size(), 4);
144  EXPECT_EQ(vec2[0], "p");
145  EXPECT_EQ(vec2[1], "px");
146  EXPECT_EQ(vec2[2], "py");
147  EXPECT_EQ(vec2[3], "pz");
148 
149  // Test alias
150  EXPECT_B2FATAL(Manager::Instance().getVariable("myAlias"));
151  Manager::Instance().addAlias("myAlias", "daughterSumOf(daughter(1, extraInfo(signalProbability)))");
152  const Manager::Var* aliasDoesExists = Manager::Instance().getVariable("myAlias");
153  EXPECT_TRUE(aliasDoesExists != nullptr);
154 
155  // aliases also should work recursively
156  auto& vm = Manager::Instance();
157  EXPECT_TRUE(vm.addAlias("myAliasAlias", "myAlias"));
158  // and it should resolve to the same variable as the original alias
159  EXPECT_EQ(aliasDoesExists, vm.getVariable("myAliasAlias"));
160 
161  // but we expect a fatal if there's a loop in alias definitions
162  EXPECT_TRUE(vm.addAlias("aliasLoop1", "aliasLoop2"));
163  EXPECT_TRUE(vm.addAlias("aliasLoop2", "aliasLoop3"));
164  EXPECT_TRUE(vm.addAlias("aliasLoop3", "aliasLoop4"));
165  EXPECT_TRUE(vm.addAlias("aliasLoop4", "aliasLoop1"));
166  EXPECT_B2FATAL(vm.getVariable("aliasLoop1"));
167  EXPECT_B2FATAL(vm.getVariable("aliasLoop3"));
168 
169  // redefine the alias with the same values is fine
170  EXPECT_NO_B2WARNING(Manager::Instance().addAlias("myAlias", "daughterSumOf(daughter(1, extraInfo(signalProbability)))"));
171  // redefine the alias with a different value gives an error
172  EXPECT_B2WARNING(Manager::Instance().addAlias("myAlias", "daughterSumOf(daughter(0, extraInfo(signalProbability)))"));
173  // creating an alias for a known variables doesn't work and gives an error
174  EXPECT_B2ERROR(Manager::Instance().addAlias("M", "daughterSumOf(daughter(1, extraInfo(signalProbability)))"));
175 
176  //re-registration not allowed
177  EXPECT_B2FATAL(Manager::Instance().registerVariable("p", (Manager::FunctionPtr)&dummyVar, "description",
178  Manager::VariableDataType::c_double));
179 
180  EXPECT_B2FATAL(Manager::Instance().registerVariable("something", (Manager::FunctionPtr)nullptr, "blah",
181  Manager::VariableDataType::c_double));
182 
183 
184  Manager::Instance().registerVariable("testingthedummyvar", (Manager::FunctionPtr)&dummyVar, "blah",
185  Manager::VariableDataType::c_double);
186  const Manager::Var* dummy = Manager::Instance().getVariable("testingthedummyvar");
187  ASSERT_NE(dummy, nullptr);
188  EXPECT_TRUE(dummy->description == "blah");
189  EXPECT_DOUBLE_EQ(std::get<double>(dummy->function(nullptr)), 42.0);
190 
191  //also test the macro (with other name)
192  REGISTER_VARIABLE("testingthedummyvar2", dummyVar, "something else");
193  dummy = Manager::Instance().getVariable("testingthedummyvar2");
194  ASSERT_NE(dummy, nullptr);
195  EXPECT_TRUE(dummy->description == "something else");
196  EXPECT_DOUBLE_EQ(std::get<double>(dummy->function(nullptr)), 42.0);
197 
198 
199  Manager::Instance().registerVariable("testingthedummyvarwithparameters(n)", (Manager::ParameterFunctionPtr)&dummyVarWithParameters,
200  "blah", Manager::VariableDataType::c_double);
201  dummy = Manager::Instance().getVariable("testingthedummyvarwithparameters(3)");
202  ASSERT_NE(dummy, nullptr);
203  EXPECT_DOUBLE_EQ(std::get<double>(dummy->function(nullptr)), 3.0);
204  EXPECT_DOUBLE_EQ(std::get<double>(Manager::Instance().getVariable("testingthedummyvarwithparameters(3)")->function(nullptr)), 3.0);
205  EXPECT_DOUBLE_EQ(std::get<double>(Manager::Instance().getVariable("testingthedummyvarwithparameters(3,5)")->function(nullptr)),
206  8.0);
207  EXPECT_DOUBLE_EQ(std::get<double>(Manager::Instance().getVariable("testingthedummyvarwithparameters(3,7,8)")->function(nullptr)),
208  18.0);
209 
210  Manager::Instance().registerVariable("testingthedummymetavar(cut)", (Manager::MetaFunctionPtr)&dummyMetaVar,
211  "blah", Manager::VariableDataType::c_double);
212  dummy = Manager::Instance().getVariable("testingthedummymetavar(1 < 2)");
213  ASSERT_NE(dummy, nullptr);
214  EXPECT_DOUBLE_EQ(std::get<double>(dummy->function(nullptr)), 5.0);
215  EXPECT_DOUBLE_EQ(std::get<double>(Manager::Instance().getVariable("testingthedummymetavar(123)")->function(nullptr)), 3.0);
216 
217 
218  //also test the macro (with other name)
219  REGISTER_VARIABLE("testingthedummyvarwithparameters2(n,m)", dummyVarWithParameters, "something else");
220  dummy = Manager::Instance().getVariable("testingthedummyvarwithparameters2(4,5)");
221  ASSERT_NE(dummy, nullptr);
222  EXPECT_DOUBLE_EQ(std::get<double>(dummy->function(nullptr)), 9.0);
223 
224  //test list
225  /*
226  for (const Manager::Var* v : Manager::Instance().getVariables()) {
227  B2WARNING(v->name);
228  }
229  */
230  EXPECT_TRUE(Manager::Instance().getVariables().size() > 0);
231 
232  //special characters are not allowed!
233  EXPECT_B2FATAL(Manager::Instance().registerVariable(" space", (Manager::FunctionPtr)dummyVar, "blah",
234  Manager::VariableDataType::c_double));
235  EXPECT_B2FATAL(Manager::Instance().registerVariable("star*", (Manager::FunctionPtr)dummyVar, "blah",
236  Manager::VariableDataType::c_double));
237  EXPECT_B2FATAL(Manager::Instance().registerVariable("*", (Manager::FunctionPtr)dummyVar, "blah",
238  Manager::VariableDataType::c_double));
239 
240  //this is ok, though
241  Manager::Instance().registerVariable("abcdef0123945859432689_ZEFUEONHSUTNSXA", (Manager::FunctionPtr)dummyVar, "blah",
242  Manager::VariableDataType::c_double);
243  }
244 
245  TEST(VariableTest, Cut)
246  {
247  Manager::Instance().registerVariable("dummyvar", (Manager::FunctionPtr)&dummyVar, "blah", Manager::VariableDataType::c_double);
248  Manager::Instance().registerVariable("dummymetavar(cut)", (Manager::MetaFunctionPtr)&dummyMetaVar, "blah",
249  Manager::VariableDataType::c_double);
250 
251  std::unique_ptr<Cut> a = Cut::compile("dummyvar > 1.0");
252  EXPECT_TRUE(a->check(nullptr));
253  a = Cut::compile("1.0 < dummyvar <= dummyvar");
254  EXPECT_TRUE(a->check(nullptr));
255 
256  a = Cut::compile("dummyvar < 100.0");
257  EXPECT_TRUE(a->check(nullptr));
258  a = Cut::compile("dummyvar <= dummyvar <= dummyvar");
259  EXPECT_TRUE(a->check(nullptr));
260 
261  a = Cut::compile("dummymetavar(123) < 100.0");
262  EXPECT_TRUE(a->check(nullptr));
263  a = Cut::compile("dummymetavar(1) <= dummymetavar(1<2) <= dummymetavar(1<23)");
264  EXPECT_TRUE(a->check(nullptr));
265  }
266 
267 
268 } // namespace
This class implements a common way to implement cut/selection functionality for arbitrary objects.
Definition: GeneralCut.h:71
Class to store reconstructed particles.
Definition: Particle.h:75
std::function< VarVariant(const Particle *)> FunctionPtr
functions stored take a const Particle* and return VarVariant.
Definition: Manager.h:113
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:117
std::function< VarVariant(const Particle *, const std::vector< double > &)> ParameterFunctionPtr
parameter functions stored take a const Particle*, const std::vector<double>& and return VarVariant.
Definition: Manager.h:115
TEST(TestgetDetectorRegion, TestgetDetectorRegion)
Test Constructors.
Abstract base class for different kinds of events.
std::string description
Description of what this function does.
Definition: Manager.h:131
A variable returning a floating-point value for a given Particle.
Definition: Manager.h:146
FunctionPtr function
Pointer to function.
Definition: Manager.h:147