Belle II Software development
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
15using namespace std;
16using namespace Belle2;
17using namespace Belle2::Variable;
18namespace {
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
static std::unique_ptr< GeneralCut > compile(const std::string &cut)
Creates an instance of a cut and returns a unique_ptr to it, if you need a copy-able object instead y...
Definition: GeneralCut.h:84
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::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:179
const Var * getVariable(std::string name)
Get the variable belonging to the given key.
Definition: Manager.cc:57
static Manager & Instance()
get singleton instance.
Definition: Manager.cc:25
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
bool addAlias(const std::string &alias, const std::string &variable)
Add alias Return true if the alias was successfully added.
Definition: Manager.cc:95
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
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.
Definition: Manager.cc:331
Abstract base class for different kinds of events.
STL namespace.
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