Belle II Software development
variables.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
9#include <analysis/variables/Variables.h>
10#include <analysis/variables/BasicParticleInformation.h>
11#include <analysis/variables/VertexVariables.h>
12#include <analysis/variables/PIDVariables.h>
13#include <analysis/variables/TrackVariables.h>
14
15#include <analysis/VariableManager/Manager.h>
16
17#include <analysis/dataobjects/Particle.h>
18#include <analysis/dataobjects/ParticleExtraInfoMap.h>
19#include <analysis/dataobjects/ParticleList.h>
20#include <framework/dataobjects/EventExtraInfo.h>
21#include <analysis/utility/ReferenceFrame.h>
22
23#include <framework/datastore/StoreArray.h>
24#include <framework/datastore/StoreObjPtr.h>
25#include <framework/utilities/TestHelpers.h>
26#include <framework/gearbox/Gearbox.h>
27#include <framework/gearbox/Const.h>
28
29#include <mdst/dataobjects/MCParticle.h>
30#include <mdst/dataobjects/MCParticleGraph.h>
31#include <mdst/dataobjects/PIDLikelihood.h>
32#include <mdst/dataobjects/Track.h>
33#include <mdst/dataobjects/V0.h>
34#include <mdst/dataobjects/ECLCluster.h>
35
36#include <gtest/gtest.h>
37
38#include <TMatrixFSym.h>
39#include <TRandom3.h>
40#include <Math/Cartesian2D.h>
41#include <Math/Vector3D.h>
42#include <Math/Vector4D.h>
43#include <utility>
44
45using namespace std;
46using namespace Belle2;
47using namespace Belle2::Variable;
48using namespace ROOT::Math;
49
50namespace {
51
53 TEST(KinematicVariableTest, Variable)
54 {
55
56 // Connect gearbox for CMS variables
57
58 Gearbox& gearbox = Gearbox::getInstance();
59 gearbox.setBackends({std::string("file:")});
60 gearbox.close();
61 gearbox.open("geometry/Belle2.xml", false);
62
63 {
64 Particle pH({0.290582573157898, 0, 6.99796952744559, 7.004}, 11);
65 Particle pL({0.166035330010433, 0, -3.99855423973071, 4.002}, -11);
66
67 Particle p({0, 0.999999869440028, 0, 1.0}, -11);
68 const double eps = 1e-15;
70
71 EXPECT_NEAR(0.0, particlePx(&pH), eps);
72 EXPECT_NEAR(0.0, particlePy(&pH), eps);
73 EXPECT_NEAR(0.0, particlePx(&pL), eps);
74 EXPECT_NEAR(0.0, particlePy(&pL), eps);
75 EXPECT_FLOAT_EQ(5.289778893721573, particlePz(&pH));
76 EXPECT_FLOAT_EQ(-5.289778893721573, particlePz(&pL));
77 EXPECT_FLOAT_EQ(10.579557836806245064 / 2, particleE(&pH));
78 EXPECT_FLOAT_EQ(10.579557836806245064 / 2, particleE(&pL));
79
80 EXPECT_FLOAT_EQ(0.999999869440028, particlePy(&p));
81 }
82
83 {
84 Particle p({ 0.1, -0.4, 0.8, 1.0 }, 411);
85
86 TMatrixFSym error(7);
87 error.Zero();
88 error(0, 0) = 0.05;
89 error(1, 1) = 0.2;
90 error(2, 2) = 0.4;
91 error(0, 1) = -0.1;
92 error(0, 2) = 0.9;
93 p.setMomentumVertexErrorMatrix(error);
94
95 EXPECT_FLOAT_EQ(0.9, particleP(&p));
96 EXPECT_FLOAT_EQ(1.0, particleE(&p));
97 EXPECT_FLOAT_EQ(0.1, particlePx(&p));
98 EXPECT_FLOAT_EQ(-0.4, particlePy(&p));
99 EXPECT_FLOAT_EQ(0.8, particlePz(&p));
100 EXPECT_FLOAT_EQ(0.412310562, particlePt(&p));
101 EXPECT_FLOAT_EQ(0.8 / 0.9, particleCosTheta(&p));
102 EXPECT_FLOAT_EQ(-1.325817664, particlePhi(&p));
103
104 EXPECT_FLOAT_EQ(0.737446378, particlePErr(&p));
105 EXPECT_FLOAT_EQ(sqrt(0.05), particlePxErr(&p));
106 EXPECT_FLOAT_EQ(sqrt(0.2), particlePyErr(&p));
107 EXPECT_FLOAT_EQ(sqrt(0.4), particlePzErr(&p));
108 EXPECT_FLOAT_EQ(0.488093530, particlePtErr(&p));
109 EXPECT_FLOAT_EQ(0.156402664, particleCosThetaErr(&p));
110 EXPECT_FLOAT_EQ(0.263066820, particlePhiErr(&p));
111
112
113 {
115 EXPECT_FLOAT_EQ(0.68174648, particleP(&p));
116 EXPECT_FLOAT_EQ(0.80918372, particleE(&p));
117 EXPECT_FLOAT_EQ(0.058562335, particlePx(&p));
118 EXPECT_FLOAT_EQ(-0.40000001, particlePy(&p));
119 EXPECT_FLOAT_EQ(0.5489524, particlePz(&p));
120 EXPECT_FLOAT_EQ(0.40426421, particlePt(&p));
121 EXPECT_FLOAT_EQ(0.80521482, particleCosTheta(&p));
122 EXPECT_FLOAT_EQ(-1.4254233, particlePhi(&p));
123
124 EXPECT_FLOAT_EQ(sqrt(0.2), particlePyErr(&p));
125 }
126
127 {
129 EXPECT_ALL_NEAR(particleP(&p), 0.0, 1e-9);
130 EXPECT_FLOAT_EQ(0.4358899, particleE(&p));
131 EXPECT_ALL_NEAR(0.0, particlePx(&p), 1e-9);
132 EXPECT_ALL_NEAR(0.0, particlePy(&p), 1e-9);
133 EXPECT_ALL_NEAR(0.0, particlePz(&p), 1e-9);
134 EXPECT_ALL_NEAR(0.0, particlePt(&p), 1e-9);
135
136 }
137
138 {
140 EXPECT_FLOAT_EQ(0.9, particleP(&p));
141 EXPECT_FLOAT_EQ(1.0, particleE(&p));
142 EXPECT_FLOAT_EQ(0.1, particlePx(&p));
143 EXPECT_FLOAT_EQ(-0.4, particlePy(&p));
144 EXPECT_FLOAT_EQ(0.8, particlePz(&p));
145 EXPECT_FLOAT_EQ(0.412310562, particlePt(&p));
146 EXPECT_FLOAT_EQ(0.8 / 0.9, particleCosTheta(&p));
147 EXPECT_FLOAT_EQ(-1.325817664, particlePhi(&p));
148
149 EXPECT_FLOAT_EQ(0.737446378, particlePErr(&p));
150 EXPECT_FLOAT_EQ(sqrt(0.05), particlePxErr(&p));
151 EXPECT_FLOAT_EQ(sqrt(0.2), particlePyErr(&p));
152 EXPECT_FLOAT_EQ(sqrt(0.4), particlePzErr(&p));
153 EXPECT_FLOAT_EQ(0.488093530, particlePtErr(&p));
154 EXPECT_FLOAT_EQ(0.156402664, particleCosThetaErr(&p));
155 EXPECT_FLOAT_EQ(0.263066820, particlePhiErr(&p));
156 }
157
158 {
159 UseReferenceFrame<RotationFrame> dummy(XYZVector(1, 0, 0), XYZVector(0, 1, 0), XYZVector(0, 0, 1));
160 EXPECT_FLOAT_EQ(0.9, particleP(&p));
161 EXPECT_FLOAT_EQ(1.0, particleE(&p));
162 EXPECT_FLOAT_EQ(0.1, particlePx(&p));
163 EXPECT_FLOAT_EQ(-0.4, particlePy(&p));
164 EXPECT_FLOAT_EQ(0.8, particlePz(&p));
165 EXPECT_FLOAT_EQ(0.412310562, particlePt(&p));
166 EXPECT_FLOAT_EQ(0.8 / 0.9, particleCosTheta(&p));
167 EXPECT_FLOAT_EQ(-1.325817664, particlePhi(&p));
168
169 EXPECT_FLOAT_EQ(0.737446378, particlePErr(&p));
170 EXPECT_FLOAT_EQ(sqrt(0.05), particlePxErr(&p));
171 EXPECT_FLOAT_EQ(sqrt(0.2), particlePyErr(&p));
172 EXPECT_FLOAT_EQ(sqrt(0.4), particlePzErr(&p));
173 EXPECT_FLOAT_EQ(0.488093530, particlePtErr(&p));
174 EXPECT_FLOAT_EQ(0.156402664, particleCosThetaErr(&p));
175 EXPECT_FLOAT_EQ(0.263066820, particlePhiErr(&p));
176
177 const auto& frame = ReferenceFrame::GetCurrent();
178 EXPECT_FLOAT_EQ(-0.1, frame.getMomentumErrorMatrix(&p)(0, 1));
179 EXPECT_FLOAT_EQ(0.9, frame.getMomentumErrorMatrix(&p)(0, 2));
180 }
181
182 {
183 UseReferenceFrame<RotationFrame> dummy(XYZVector(1, 0, 0), XYZVector(0, 0, -1), XYZVector(0, 1, 0));
184 EXPECT_FLOAT_EQ(0.9, particleP(&p));
185 EXPECT_FLOAT_EQ(1.0, particleE(&p));
186 EXPECT_FLOAT_EQ(0.1, particlePx(&p));
187 EXPECT_FLOAT_EQ(-0.8, particlePy(&p));
188 EXPECT_FLOAT_EQ(-0.4, particlePz(&p));
189
190 EXPECT_FLOAT_EQ(0.737446378, particlePErr(&p));
191 EXPECT_FLOAT_EQ(sqrt(0.05), particlePxErr(&p));
192 EXPECT_FLOAT_EQ(sqrt(0.4), particlePyErr(&p));
193 EXPECT_FLOAT_EQ(sqrt(0.2), particlePzErr(&p));
194
195 const auto& frame = ReferenceFrame::GetCurrent();
196 EXPECT_FLOAT_EQ(-0.9, frame.getMomentumErrorMatrix(&p)(0, 1));
197 EXPECT_FLOAT_EQ(-0.1, frame.getMomentumErrorMatrix(&p)(0, 2));
198 }
199
200 {
201 UseReferenceFrame<CMSRotationFrame> dummy(XYZVector(1, 0, 0), XYZVector(0, 1, 0), XYZVector(0, 0, 1));
202 EXPECT_FLOAT_EQ(0.68174648, particleP(&p));
203 EXPECT_FLOAT_EQ(0.80918372, particleE(&p));
204 EXPECT_FLOAT_EQ(0.058562335, particlePx(&p));
205 EXPECT_FLOAT_EQ(-0.40000001, particlePy(&p));
206 EXPECT_FLOAT_EQ(0.5489524, particlePz(&p));
207 EXPECT_FLOAT_EQ(0.40426421, particlePt(&p));
208 EXPECT_FLOAT_EQ(0.80521482, particleCosTheta(&p));
209 EXPECT_FLOAT_EQ(-1.4254233, particlePhi(&p));
210
211 EXPECT_FLOAT_EQ(sqrt(0.2), particlePyErr(&p));
212 }
213
214 {
215 Particle pinv({ -0.1, 0.4, -0.8, 1.0 }, 411);
216 UseReferenceFrame<RestFrame> dummy(&pinv);
217 Particle p2({ 0.0, 0.0, 0.0, 0.4358899}, 411);
218 EXPECT_FLOAT_EQ(0.9, particleP(&p2));
219 EXPECT_FLOAT_EQ(1.0, particleE(&p2));
220 EXPECT_FLOAT_EQ(0.1, particlePx(&p2));
221 EXPECT_FLOAT_EQ(-0.4, particlePy(&p2));
222 EXPECT_FLOAT_EQ(0.8, particlePz(&p2));
223 EXPECT_FLOAT_EQ(0.412310562, particlePt(&p2));
224 EXPECT_FLOAT_EQ(0.8 / 0.9, particleCosTheta(&p2));
225 EXPECT_FLOAT_EQ(-1.325817664, particlePhi(&p2));
226 }
227 }
228
229 {
230 Particle p({ 0.0, 0.0, 0.0, 0.0 }, 411);
231 EXPECT_FLOAT_EQ(0.0, particleP(&p));
232 EXPECT_FLOAT_EQ(0.0, particleE(&p));
233 EXPECT_FLOAT_EQ(0.0, particlePx(&p));
234 EXPECT_FLOAT_EQ(0.0, particlePy(&p));
235 EXPECT_FLOAT_EQ(0.0, particlePz(&p));
236 EXPECT_FLOAT_EQ(0.0, particlePt(&p));
237 EXPECT_FLOAT_EQ(1.0, particleCosTheta(&p));
238 EXPECT_FLOAT_EQ(0.0, particlePhi(&p));
239
241 EXPECT_FLOAT_EQ(0.0, particleP(&p));
242 EXPECT_FLOAT_EQ(0.0, particleE(&p));
243 EXPECT_FLOAT_EQ(0.0, particlePx(&p));
244 EXPECT_FLOAT_EQ(0.0, particlePy(&p));
245 EXPECT_FLOAT_EQ(0.0, particlePz(&p));
246 EXPECT_FLOAT_EQ(0.0, particlePt(&p));
247 EXPECT_FLOAT_EQ(1.0, particleCosTheta(&p));
248 EXPECT_FLOAT_EQ(0.0, particlePhi(&p));
249 }
250
251 {
253 StoreArray<Particle> particles;
254 particles.registerInDataStore();
257 PxPyPzEVector vec0 = {0.0, 0.0, 0.0, T.getCMSEnergy()};
258 PxPyPzEVector vec1 = {0.0, +0.332174566, 0.0, T.getCMSEnergy() / 2.};
259 PxPyPzEVector vec2 = {0.0, -0.332174566, 0.0, T.getCMSEnergy() / 2.};
260 Particle* p0 = particles.appendNew(Particle(T.rotateCmsToLab() * vec0, 22));
261 Particle* p1 = particles.appendNew(Particle(T.rotateCmsToLab() * vec1, 22, Particle::c_Unflavored, Particle::c_Undefined, 1));
262 Particle* p2 = particles.appendNew(Particle(T.rotateCmsToLab() * vec2, 22, Particle::c_Unflavored, Particle::c_Undefined, 2));
263
264 p0->appendDaughter(p1->getArrayIndex());
265 p0->appendDaughter(p2->getArrayIndex());
266
267 EXPECT_ALL_NEAR(m2RecoilSignalSide(p0), 0.0, 1e-7);
268 }
269
270
271 }
272
273
274 TEST(VertexVariableTest, Variable)
275 {
276
277 // Connect gearbox for CMS variables
278
279 Gearbox& gearbox = Gearbox::getInstance();
280 gearbox.setBackends({std::string("file:")});
281 gearbox.close();
282 gearbox.open("geometry/Belle2.xml", false);
283
284 Particle p({ 0.1, -0.4, 0.8, 1.0 }, 11);
285 p.setPValue(0.5);
286 p.setVertex(XYZVector(1.0, 2.0, 2.0));
287
288 EXPECT_FLOAT_EQ(1.0, particleDX(&p));
289 EXPECT_FLOAT_EQ(2.0, particleDY(&p));
290 EXPECT_FLOAT_EQ(2.0, particleDZ(&p));
291 EXPECT_FLOAT_EQ(std::sqrt(5.0), particleDRho(&p));
292 EXPECT_FLOAT_EQ(3.0, particleDistance(&p));
293 EXPECT_FLOAT_EQ(0.5, particlePvalue(&p));
294
295 {
297 EXPECT_FLOAT_EQ(1.026177, particleDX(&p));
298 EXPECT_FLOAT_EQ(2.0, particleDY(&p));
299 EXPECT_FLOAT_EQ(2.2568872, particleDZ(&p));
300 EXPECT_FLOAT_EQ(hypot(2.0, 1.026177), particleDRho(&p));
301 EXPECT_FLOAT_EQ(3.1853695, particleDistance(&p));
302 EXPECT_FLOAT_EQ(0.5, particlePvalue(&p));
303 }
304
305 {
306 Particle p2({ 0.1, -0.4, 0.8, 1.0 }, 11);
307 p2.setPValue(0.5);
308 p2.setVertex(XYZVector(1.0, 2.0, 2.0));
309
311 EXPECT_FLOAT_EQ(0.0, particleDX(&p));
312 EXPECT_FLOAT_EQ(0.0, particleDY(&p));
313 EXPECT_FLOAT_EQ(0.0, particleDZ(&p));
314 EXPECT_FLOAT_EQ(0.0, particleDRho(&p));
315 EXPECT_FLOAT_EQ(0.0, particleDistance(&p));
316 EXPECT_FLOAT_EQ(0.5, particlePvalue(&p));
317 }
318
319 /* Test with a distance between mother and daughter vertex. One
320 * has to calculate the result by hand to test the code....
321
322 {
323 Particle p2({ 0.0 , 1.0, 0.0, 1.0 }, 11);
324 p2.setPValue(0.5);
325 p2.setVertex(XYZVector(1.0, 0.0, 2.0));
326
327 UseReferenceFrame<RestFrame> dummy(&p2);
328 EXPECT_FLOAT_EQ(0.0, particleDX(&p));
329 EXPECT_FLOAT_EQ(2.0, particleDY(&p));
330 EXPECT_FLOAT_EQ(0.0, particleDZ(&p));
331 EXPECT_FLOAT_EQ(2.0, particleDRho(&p));
332 EXPECT_FLOAT_EQ(2.0, particleDistance(&p));
333 EXPECT_FLOAT_EQ(0.5, particlePvalue(&p));
334 }
335 */
336
337 }
338
339 TEST(TrackVariablesTest, Variable)
340 {
343 StoreArray<Track> myTracks;
344 StoreArray<V0> myV0s;
345 StoreArray<Particle> myParticles;
346 myResults.registerInDataStore();
347 myTracks.registerInDataStore();
348 myV0s.registerInDataStore();
349 myParticles.registerInDataStore();
351
352 TRandom3 generator;
353
354 const float pValue = 0.5;
355 const float bField = 1.5;
356 const int charge = 1;
357 TMatrixDSym cov6(6);
358
359 // Generate a random put orthogonal pair of vectors in the r-phi plane
360 ROOT::Math::Cartesian2D d(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
361 ROOT::Math::Cartesian2D pt(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
362 d.SetXY(d.X(), -(d.X()*pt.X()) / pt.Y());
363
364 // Add a random z component
365 ROOT::Math::XYZVector position(d.X(), d.Y(), generator.Uniform(-1, 1));
366 ROOT::Math::XYZVector momentum(pt.X(), pt.Y(), generator.Uniform(-1, 1));
367
368 auto CDCValue = static_cast<unsigned long long int>(0x300000000000000);
369
370 myResults.appendNew(position, momentum, cov6, charge, Const::electron, pValue, bField, CDCValue, 16777215, 0);
371 Track mytrack;
373 Track* savedTrack = myTracks.appendNew(mytrack);
374
375 Particle* part = myParticles.appendNew(savedTrack, Const::ChargedStable(11));
376
377 const Manager::Var* vIsFromECL = Manager::Instance().getVariable("isFromECL");
378 const Manager::Var* vIsFromKLM = Manager::Instance().getVariable("isFromKLM");
379 const Manager::Var* vIsFromTrack = Manager::Instance().getVariable("isFromTrack");
380 const Manager::Var* vIsFromV0 = Manager::Instance().getVariable("isFromV0");
381
382 EXPECT_TRUE(std::get<bool>(vIsFromTrack->function(part)));
383 EXPECT_FALSE(std::get<bool>(vIsFromECL->function(part)));
384 EXPECT_FALSE(std::get<bool>(vIsFromKLM->function(part)));
385 EXPECT_FALSE(std::get<bool>(vIsFromV0->function(part)));
386 EXPECT_FLOAT_EQ(0.5, trackPValue(part));
387 EXPECT_FLOAT_EQ(position.Z(), trackZ0(part));
388 EXPECT_FLOAT_EQ(position.Rho(), trackD0(part));
389 EXPECT_FLOAT_EQ(particleDRho(part), std::fabs(trackD0FromIP(part)));
390 EXPECT_FLOAT_EQ(particleDZ(part), trackZ0FromIP(part));
391 EXPECT_FLOAT_EQ(3, trackNCDCHits(part));
392 EXPECT_FLOAT_EQ(24, trackNSVDHits(part));
393 EXPECT_FLOAT_EQ(12, trackNPXDHits(part));
394
395 //-----------------------------------------------------------------------
396 // now add another track and mock up a V0 and a V0-based particle
397 myResults.appendNew(position, momentum, cov6, charge * -1,
398 Const::electron, pValue, bField, CDCValue, 16777215, 0);
399 Track secondTrack;
401 Track* savedTrack2 = myTracks.appendNew(secondTrack);
402 myParticles.appendNew(savedTrack2, Const::ChargedStable(11));
403 myV0s.appendNew(V0(std::pair(savedTrack, myResults[0]), std::pair(savedTrack2, myResults[1]), 0.0, 0.0, 0.0));
404 const PxPyPzEVector v0Momentum(2 * momentum.X(), 2 * momentum.Y(), 2 * momentum.Z(), (momentum * 2).R());
405 auto v0particle = myParticles.appendNew(v0Momentum, 22,
406 Particle::c_Unflavored, Particle::c_V0, 0);
407 v0particle->appendDaughter(0, false);
408 v0particle->appendDaughter(1, false);
409 //-----------------------------------------------------------------------
410
411 EXPECT_FALSE(std::get<bool>(vIsFromTrack->function(v0particle)));
412 EXPECT_FALSE(std::get<bool>(vIsFromECL->function(v0particle)));
413 EXPECT_FALSE(std::get<bool>(vIsFromKLM->function(v0particle)));
414 EXPECT_TRUE(std::get<bool>(vIsFromV0->function(v0particle)));
415
416 const Manager::Var* vNDaughters = Manager::Instance().getVariable("nDaughters");
417 EXPECT_EQ(std::get<int>(vNDaughters->function(v0particle)), 2);
418 }
419
420 class MCTruthVariablesTest : public ::testing::Test {
421 protected:
422 virtual void SetUp()
423 {
424 // datastore things
427
428 // needed to mock up
429 StoreArray<ECLCluster> clusters;
430 StoreArray<MCParticle> mcparticles;
431 StoreArray<Track> tracks;
433 StoreArray<Particle> particles;
434
435 // register the arrays
436 clusters.registerInDataStore();
437 mcparticles.registerInDataStore();
438 tracks.registerInDataStore();
439 trackfits.registerInDataStore();
440 particles.registerInDataStore();
441
442 // register the relations for mock up mcmatching
443 clusters.registerRelationTo(mcparticles);
444 tracks.registerRelationTo(mcparticles);
445 particles.registerRelationTo(mcparticles);
446
447 // register the relation for mock up track <--> cluster matching
448 //clusters.registerRelationTo(tracks);
449 tracks.registerRelationTo(clusters);
450
451 // end datastore things
453
454 /* mock up an electron (track with a cluster AND a track-cluster match)
455 * and a photon (cluster, no track) and MCParticles for both
456 *
457 * this assumes that everything (tracking, clustering, track-cluster
458 * matching *and* mcmatching all worked)
459 *
460 * this can be extended to pions, kaons, etc but leave it simple for now
461 */
462
463 // create the true underlying mcparticles
464 auto* true_photon = mcparticles.appendNew(MCParticle());
465 true_photon->setPDG(Const::photon.getPDGCode());
466 auto* true_electron = mcparticles.appendNew(MCParticle());
467 true_electron->setPDG(Const::electron.getPDGCode());
468 auto* true_pion = mcparticles.appendNew(MCParticle());
469 true_pion->setPDG(-Const::pion.getPDGCode());
470
471 // create the reco clusters
472 auto* cl0 = clusters.appendNew(ECLCluster());
473 cl0->setEnergy(1.0);
474 cl0->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
475 cl0->setClusterId(0);
476
477 auto* cl1 = clusters.appendNew(ECLCluster());
478 cl1->setEnergy(0.5);
479 cl1->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
480 cl1->setClusterId(1);
481
482 // create a reco track (one has to also mock up a track fit result)
483 TMatrixDSym cov(6);
484 trackfits.appendNew(
485 ROOT::Math::XYZVector(), ROOT::Math::XYZVector(), cov, -1, Const::electron, 0.5, 1.5,
486 static_cast<unsigned long long int>(0x300000000000000), 16777215, 0);
487 auto* electron_tr = tracks.appendNew(Track());
488 electron_tr->setTrackFitResultIndex(Const::electron, 0);
489 electron_tr->addRelationTo(cl1); // a track <--> cluster match
490
491 TMatrixDSym cov1(6);
492 trackfits.appendNew(
493 ROOT::Math::XYZVector(), ROOT::Math::XYZVector(), cov1, -1, Const::pion, 0.51, 1.5,
494 static_cast<unsigned long long int>(0x300000000000000), 16777215, 0);
495 auto* pion_tr = tracks.appendNew(Track());
496 pion_tr->setTrackFitResultIndex(Const::pion, 0);
497 pion_tr->addRelationTo(cl1); // a track <--> cluster match
498
499 // now set mcmatch relations
500 cl0->addRelationTo(true_photon, 12.3);
501 cl0->addRelationTo(true_electron, 2.3);
502 cl1->addRelationTo(true_electron, 45.6);
503 cl1->addRelationTo(true_photon, 5.6);
504 cl1->addRelationTo(true_pion, 15.6);
505
506 electron_tr->addRelationTo(true_electron);
507 pion_tr->addRelationTo(true_pion);
508
509 // create belle2::Particles from the mdst objects
510 const auto* photon = particles.appendNew(Particle(cl0));
511 const auto* electron = particles.appendNew(Particle(electron_tr, Const::electron));
512 const auto* pion = particles.appendNew(Particle(pion_tr, Const::pion));
513 const auto* misid_photon = particles.appendNew(Particle(cl1));
514
515 // now set mcmatch relations
516 photon->addRelationTo(true_photon);
517 electron->addRelationTo(true_electron);
518 pion->addRelationTo(true_pion);
519 misid_photon->addRelationTo(true_electron); // assume MC matching caught this
520 }
521
522 virtual void TearDown()
523 {
525 }
526 };
527
528 TEST_F(MCTruthVariablesTest, mcCosThetaBetweenParticleAndNominalB)
529 {
532 StoreArray<MCParticle> mcParticles;
533 StoreArray<Particle> particles;
534 particles.registerInDataStore();
535 mcParticles.registerInDataStore();
536 particles.registerRelationTo(mcParticles);
538
539 // Create MC graph for B- -> (D0 -> K- e+ nu_e) pi-
540 MCParticleGraph mcGraph;
541
542 MCParticleGraph::GraphParticle& graphParticleMother = mcGraph.addParticle();
543 MCParticleGraph::GraphParticle& graphParticleDaughter1 = mcGraph.addParticle();
544 MCParticleGraph::GraphParticle& graphParticleDaughter2 = mcGraph.addParticle();
545 MCParticleGraph::GraphParticle& graphParticleGranddaughter1 = mcGraph.addParticle();
546 MCParticleGraph::GraphParticle& graphParticleGranddaughter2 = mcGraph.addParticle();
547 MCParticleGraph::GraphParticle& graphParticleGranddaughter3 = mcGraph.addParticle();
548
549 graphParticleDaughter1.comesFrom(graphParticleMother);
550 graphParticleDaughter2.comesFrom(graphParticleMother);
551 graphParticleGranddaughter1.comesFrom(graphParticleDaughter1);
552 graphParticleGranddaughter2.comesFrom(graphParticleDaughter1);
553 graphParticleGranddaughter3.comesFrom(graphParticleDaughter1);
554
555 graphParticleMother.setPDG(-521);
556 graphParticleDaughter1.setPDG(421);
557 graphParticleDaughter2.setPDG(-Const::pion.getPDGCode());
558 graphParticleGranddaughter1.setPDG(-Const::kaon.getPDGCode());
559 graphParticleGranddaughter2.setPDG(-Const::electron.getPDGCode());
560 graphParticleGranddaughter3.setPDG(12);
561
562 // Create the two 4-vectors that will factor into calculation, and set a mass that corresponds
563 // to the length of the 4-vector
565 graphParticleMother.set4Vector(T.rotateCmsToLab() * PxPyPzEVector(3.0, 4.0, 5.0, 18.0));
566 graphParticleGranddaughter3.set4Vector(T.rotateCmsToLab() * PxPyPzEVector(0.0, 0.0, 5.0, 5.0));
567 graphParticleMother.setMass(16.55294535724685);
568
569 // The following masses and momenta do not factor into the calculation, but we will set them non-zero
570 PxPyPzEVector dummyP4(1, 2, 1, 5);
571 double dummyM = 4.3589;
572 graphParticleDaughter1.set4Vector(dummyP4);
573 graphParticleDaughter1.setMass(dummyM);
574 graphParticleDaughter2.set4Vector(dummyP4);
575 graphParticleDaughter2.setMass(dummyM);
576 graphParticleGranddaughter1.set4Vector(dummyP4);
577 graphParticleGranddaughter1.setMass(dummyM);
578 graphParticleGranddaughter2.set4Vector(dummyP4);
579 graphParticleGranddaughter2.setMass(dummyM);
580
581 mcGraph.generateList();
582
583 // Create mockup particles and add relations to MC particles
584 auto* pMother = particles.appendNew(dummyP4, -521);
585 pMother->addRelationTo(mcParticles[0]);
586
587 particles.appendNew(dummyP4, 421)->addRelationTo(mcParticles[1]);
588 particles.appendNew(dummyP4, -211)->addRelationTo(mcParticles[2]);
589 particles.appendNew(dummyP4, -321)->addRelationTo(mcParticles[3]);
590 particles.appendNew(dummyP4, -11)->addRelationTo(mcParticles[4]);
591 particles.appendNew(dummyP4, 12)->addRelationTo(mcParticles[5]);
592
593 double E_B = T.getCMSEnergy() / 2.0;
594 double M_B = pMother->getPDGMass();
595 double p_B = std::sqrt(E_B * E_B - M_B * M_B);
596
597 PxPyPzEVector p4_Y_CMS = T.rotateLabToCms() * (graphParticleMother.get4Vector() - graphParticleGranddaughter3.get4Vector());
598 double E_Y = p4_Y_CMS.E(); // E_Mother - E_Granddaughter3
599 double p_Y = p4_Y_CMS.P(); // |p_Mother - p_Granddaughter3|
600 double M_Y = p4_Y_CMS.M(); // sqrt((p4_Mother - p4_Granddaughter3)^2)
601
602 double expectedCosBY = (2 * E_B * E_Y - M_B * M_B - M_Y * M_Y) / (2 * p_B * p_Y);
603
604 const auto* mcCosBY = Manager::Instance().getVariable("mcCosThetaBetweenParticleAndNominalB");
605
606 EXPECT_NEAR(std::get<double>(mcCosBY->function(pMother)), expectedCosBY, 1e-4);
607 }
608
609 TEST_F(MCTruthVariablesTest, ECLMCMatchWeightVariable)
610 {
611 StoreArray<Particle> particles{};
612 const auto* photon = particles[0];
613 const auto* electron = particles[1];
614 const auto* pion = particles[2];
615
616 const auto* weight = Manager::Instance().getVariable("clusterMCMatchWeight");
617 EXPECT_FLOAT_EQ(std::get<double>(weight->function(photon)), 12.3);
618 EXPECT_FLOAT_EQ(std::get<double>(weight->function(electron)), 45.6);
619 EXPECT_FLOAT_EQ(std::get<double>(weight->function(pion)), 15.6);
620 }
621
622 TEST_F(MCTruthVariablesTest, ECLBestMCMatchVariables)
623 {
624 StoreArray<Particle> particles{};
625 const auto* photon = particles[0];
626 const auto* electron = particles[1];
627 const auto* pion = particles[2];
628 const auto* misid_photon = particles[3];
629
630
631 const auto* pdgcode = Manager::Instance().getVariable("clusterBestMCPDG");
632 EXPECT_EQ(std::get<double>(pdgcode->function(photon)), Const::photon.getPDGCode());
633 EXPECT_EQ(std::get<double>(pdgcode->function(electron)), Const::electron.getPDGCode());
634 EXPECT_EQ(std::get<double>(pdgcode->function(pion)), Const::electron.getPDGCode());
635 EXPECT_EQ(std::get<double>(pdgcode->function(misid_photon)), Const::electron.getPDGCode());
636
637 const auto* weight = Manager::Instance().getVariable("clusterBestMCMatchWeight");
638 EXPECT_FLOAT_EQ(std::get<double>(weight->function(photon)), 12.3);
639 EXPECT_FLOAT_EQ(std::get<double>(weight->function(electron)), 45.6);
640 EXPECT_FLOAT_EQ(std::get<double>(weight->function(pion)), 45.6);
641 EXPECT_FLOAT_EQ(std::get<double>(weight->function(misid_photon)), 45.6);
642 }
643
644
645 class EventVariableTest : public ::testing::Test {
646 protected:
648 void SetUp() override
649 {
654
655 }
656
658 void TearDown() override
659 {
661 }
662 };
663
664 TEST_F(EventVariableTest, ExperimentRunEventDateAndTime)
665 {
666 const Manager::Var* exp = Manager::Instance().getVariable("expNum");
667 const Manager::Var* run = Manager::Instance().getVariable("runNum");
668 const Manager::Var* evt = Manager::Instance().getVariable("evtNum");
669 const Manager::Var* date = Manager::Instance().getVariable("date");
670 const Manager::Var* year = Manager::Instance().getVariable("year");
671 const Manager::Var* time = Manager::Instance().getVariable("eventTimeSeconds");
672
673 // there is no EventMetaData so expect nan
674 EXPECT_FALSE(std::get<double>(date->function(nullptr)) == std::get<double>(date->function(nullptr)));
675 EXPECT_FALSE(std::get<double>(year->function(nullptr)) == std::get<double>(year->function(nullptr)));
676 EXPECT_FALSE(std::get<double>(time->function(nullptr)) == std::get<double>(time->function(nullptr)));
677
679 StoreObjPtr<EventMetaData> evtMetaData;
680 evtMetaData.registerInDataStore();
682 evtMetaData.create();
683 evtMetaData->setExperiment(1337);
684 evtMetaData->setRun(12345);
685 evtMetaData->setEvent(54321);
686 evtMetaData->setTime(1288569600e9);
687 // 01/11/2010 is the date TDR was uploaded to arXiv ... experiment's birthday?
688
689
690 // -
691 EXPECT_EQ(std::get<int>(exp->function(nullptr)), 1337);
692 EXPECT_EQ(std::get<int>(run->function(nullptr)), 12345);
693 EXPECT_EQ(std::get<int>(evt->function(nullptr)), 54321);
694 EXPECT_FLOAT_EQ(std::get<double>(date->function(nullptr)), 20101101.);
695 EXPECT_FLOAT_EQ(std::get<double>(year->function(nullptr)), 2010.);
696 EXPECT_FLOAT_EQ(std::get<double>(time->function(nullptr)), 1288569600);
697 }
698
699 TEST_F(EventVariableTest, TestGlobalCounters)
700 {
701 StoreArray<MCParticle> mcParticles; // empty
702 const Manager::Var* var = Manager::Instance().getVariable("nMCParticles");
703 EXPECT_EQ(std::get<int>(var->function(nullptr)), 0);
704
705 for (unsigned i = 0; i < 10; ++i)
706 mcParticles.appendNew();
707
708 EXPECT_EQ(std::get<int>(var->function(nullptr)), 10);
709
710 // TODO: add other counters nTracks etc in here
711 }
712
713 TEST_F(EventVariableTest, TestIfContinuumEvent_ForContinuumEvent)
714 {
716 StoreArray<MCParticle> mcParticles;
717 StoreArray<Particle> particles;
718 particles.registerRelationTo(mcParticles);
720
721 auto* mcParticle = mcParticles.appendNew();
722 mcParticle->setPDG(Const::electron.getPDGCode());
723 mcParticle->setStatus(MCParticle::c_PrimaryParticle);
724 auto* p1 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
725 p1->addRelationTo(mcParticle);
726
727 mcParticle = mcParticles.appendNew();
728 mcParticle->setPDG(-Const::electron.getPDGCode());
729 mcParticle->setStatus(MCParticle::c_PrimaryParticle);
730 auto* p2 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
731 p2->addRelationTo(mcParticle);
732
733 const Manager::Var* var = Manager::Instance().getVariable("isContinuumEvent");
734 ASSERT_NE(var, nullptr);
735 EXPECT_TRUE(std::get<bool>(var->function(p1)));
736 EXPECT_TRUE(std::get<bool>(var->function(p2)));
737 const Manager::Var* varN = Manager::Instance().getVariable("isNotContinuumEvent");
738 ASSERT_NE(varN, nullptr);
739 EXPECT_FALSE(std::get<bool>(varN->function(p1)));
740 EXPECT_FALSE(std::get<bool>(varN->function(p2)));
741 }
742
743 TEST_F(EventVariableTest, TestIfContinuumEvent_ForUpsilon4SEvent)
744 {
746 StoreArray<MCParticle> mcParticles2;
747 StoreArray<Particle> particles2;
748 particles2.registerRelationTo(mcParticles2);
750
751 auto* mcParticle = mcParticles2.appendNew();
752 mcParticle->setPDG(Const::photon.getPDGCode());
753 mcParticle->setStatus(MCParticle::c_PrimaryParticle);
754 auto* p3 = particles2.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
755 p3->addRelationTo(mcParticle);
756
757 mcParticle = mcParticles2.appendNew();
758 mcParticle->setPDG(300553);
759 mcParticle->setStatus(MCParticle::c_PrimaryParticle);
760 auto* p4 = particles2.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 300553);
761 p4->addRelationTo(mcParticle);
762
763 const Manager::Var* var2 = Manager::Instance().getVariable("isContinuumEvent");
764 ASSERT_NE(var2, nullptr);
765 EXPECT_FALSE(std::get<bool>(var2->function(p3)));
766 EXPECT_FALSE(std::get<bool>(var2->function(p4)));
767 const Manager::Var* var2N = Manager::Instance().getVariable("isNotContinuumEvent");
768 ASSERT_NE(var2N, nullptr);
769 EXPECT_TRUE(std::get<bool>(var2N->function(p3)));
770 EXPECT_TRUE(std::get<bool>(var2N->function(p4)));
771 }
772
773 TEST_F(EventVariableTest, TestIfContinuumEvent_ForWrongReconstructedUpsilon4SEvent)
774 {
776 StoreArray<MCParticle> mcParticles3;
777 StoreArray<Particle> particles3;
778 particles3.registerRelationTo(mcParticles3);
780
781 auto* mcParticle = mcParticles3.appendNew();
782 mcParticle->setPDG(Const::photon.getPDGCode());
783 mcParticle->setStatus(MCParticle::c_PrimaryParticle);
784 auto* p5 = particles3.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
785 p5->addRelationTo(mcParticle);
786
787 mcParticle = mcParticles3.appendNew();
788 mcParticle->setPDG(300553);
789 mcParticle->setStatus(MCParticle::c_PrimaryParticle);
790 auto* p6 = particles3.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 15);
791 p6->addRelationTo(mcParticle);
792
793 const Manager::Var* var3 = Manager::Instance().getVariable("isContinuumEvent");
794 ASSERT_NE(var3, nullptr);
795 EXPECT_FALSE(std::get<bool>(var3->function(p5)));
796 EXPECT_FALSE(std::get<bool>(var3->function(p6)));
797 const Manager::Var* var3N = Manager::Instance().getVariable("isNotContinuumEvent");
798 ASSERT_NE(var3N, nullptr);
799 EXPECT_TRUE(std::get<bool>(var3N->function(p5)));
800 EXPECT_TRUE(std::get<bool>(var3N->function(p6)));
801 }
802
803
804 class MetaVariableTest : public ::testing::Test {
805 protected:
807 void SetUp() override
808 {
815 }
816
818 void TearDown() override
819 {
821 }
822 };
823
824 TEST_F(MetaVariableTest, countDaughters)
825 {
826 PxPyPzEVector momentum;
827 const int nDaughters = 6;
828 StoreArray<Particle> particles;
829 std::vector<int> daughterIndices;
830 for (int i = 0; i < nDaughters; i++) {
831 Particle d(PxPyPzEVector(1, 0, 0, 3.0), (i % 2) ? 211 : -211);
832 momentum += d.get4Vector();
833 Particle* newDaughters = particles.appendNew(d);
834 daughterIndices.push_back(newDaughters->getArrayIndex());
835 }
836 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
837
838 const Manager::Var* var = Manager::Instance().getVariable("countDaughters(charge > 0)");
839 ASSERT_NE(var, nullptr);
840 EXPECT_EQ(std::get<int>(var->function(p)), 3);
841
842 var = Manager::Instance().getVariable("countDaughters(abs(charge) > 0)");
843 ASSERT_NE(var, nullptr);
844 EXPECT_EQ(std::get<int>(var->function(p)), 6);
845
846 }
847
848 TEST_F(MetaVariableTest, useRestFrame)
849 {
850 Gearbox& gearbox = Gearbox::getInstance();
851 gearbox.setBackends({std::string("file:")});
852 gearbox.close();
853 gearbox.open("geometry/Belle2.xml", false);
854
855 Particle p({ 0.1, -0.4, 0.8, 1.0 }, 411);
856 p.setVertex(XYZVector(1.0, 2.0, 2.0));
857
858 const Manager::Var* var = Manager::Instance().getVariable("p");
859 ASSERT_NE(var, nullptr);
860 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.9);
861
862 var = Manager::Instance().getVariable("E");
863 ASSERT_NE(var, nullptr);
864 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.0);
865
866 var = Manager::Instance().getVariable("distance");
867 ASSERT_NE(var, nullptr);
868 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 3.0);
869
870 var = Manager::Instance().getVariable("useRestFrame(p)");
871 ASSERT_NE(var, nullptr);
872 EXPECT_NEAR(std::get<double>(var->function(&p)), 0.0, 1e-9);
873
874 var = Manager::Instance().getVariable("useRestFrame(E)");
875 ASSERT_NE(var, nullptr);
876 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.4358899);
877
878 var = Manager::Instance().getVariable("useRestFrame(distance)");
879 ASSERT_NE(var, nullptr);
880 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.0);
881 }
882
883 TEST_F(MetaVariableTest, useLabFrame)
884 {
885 Particle p({ 0.1, -0.4, 0.8, 1.0 }, 411);
886 p.setVertex(XYZVector(1.0, 2.0, 2.0));
887
888 const Manager::Var* var = Manager::Instance().getVariable("p");
889 ASSERT_NE(var, nullptr);
890 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.9);
891
892 var = Manager::Instance().getVariable("E");
893 ASSERT_NE(var, nullptr);
894 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.0);
895
896 var = Manager::Instance().getVariable("distance");
897 ASSERT_NE(var, nullptr);
898 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 3.0);
899
900 var = Manager::Instance().getVariable("useLabFrame(p)");
901 ASSERT_NE(var, nullptr);
902 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.9);
903
904 var = Manager::Instance().getVariable("useLabFrame(E)");
905 ASSERT_NE(var, nullptr);
906 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.0);
907
908 var = Manager::Instance().getVariable("useLabFrame(distance)");
909 ASSERT_NE(var, nullptr);
910 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 3.0);
911 }
912
913 TEST_F(MetaVariableTest, useCMSFrame)
914 {
915 Gearbox& gearbox = Gearbox::getInstance();
916 gearbox.setBackends({std::string("file:")});
917 gearbox.close();
918 gearbox.open("geometry/Belle2.xml", false);
919
920 Particle p({ 0.1, -0.4, 0.8, 1.0 }, 411);
921 p.setVertex(XYZVector(1.0, 2.0, 2.0));
922
923 const Manager::Var* var = Manager::Instance().getVariable("p");
924 ASSERT_NE(var, nullptr);
925 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.9);
926
927 var = Manager::Instance().getVariable("E");
928 ASSERT_NE(var, nullptr);
929 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.0);
930
931 var = Manager::Instance().getVariable("distance");
932 ASSERT_NE(var, nullptr);
933 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 3.0);
934
935 var = Manager::Instance().getVariable("useCMSFrame(p)");
936 ASSERT_NE(var, nullptr);
937 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.68174650327489894064);
938
939 var = Manager::Instance().getVariable("useCMSFrame(E)");
940 ASSERT_NE(var, nullptr);
941 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.80918372124478121776);
942
943 var = Manager::Instance().getVariable("useCMSFrame(distance)");
944 ASSERT_NE(var, nullptr);
945 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 3.1853695);
946 }
947
948 TEST_F(MetaVariableTest, useTagSideRecoilRestFrame)
949 {
951 StoreArray<Particle> particles;
952 particles.registerInDataStore();
955 PxPyPzEVector vec0 = {0.0, 0.0, 0.0, T.getCMSEnergy()};
956 PxPyPzEVector vec1 = {0.0, +0.332174566, 0.0, T.getCMSEnergy() / 2.};
957 PxPyPzEVector vec2 = {0.0, -0.332174566, 0.0, T.getCMSEnergy() / 2.};
958 Particle* p0 = particles.appendNew(Particle(T.rotateCmsToLab() * vec0, 300553));
959 Particle* p1 = particles.appendNew(Particle(T.rotateCmsToLab() * vec1, 511, Particle::c_Unflavored, Particle::c_Undefined, 1));
960 Particle* p2 = particles.appendNew(Particle(T.rotateCmsToLab() * vec2, -511, Particle::c_Unflavored, Particle::c_Undefined, 2));
961
962 p0->appendDaughter(p1->getArrayIndex());
963 p0->appendDaughter(p2->getArrayIndex());
964
965 const Manager::Var* var = Manager::Instance().getVariable("useTagSideRecoilRestFrame(daughter(1, p), 0)");
966 ASSERT_NE(var, nullptr);
967 EXPECT_NEAR(std::get<double>(var->function(p0)), 0., 1e-6);
968
969 var = Manager::Instance().getVariable("useTagSideRecoilRestFrame(daughter(1, px), 0)");
970 ASSERT_NE(var, nullptr);
971 EXPECT_NEAR(std::get<double>(var->function(p0)), 0., 1e-6);
972
973 var = Manager::Instance().getVariable("useTagSideRecoilRestFrame(daughter(1, py), 0)");
974 ASSERT_NE(var, nullptr);
975 EXPECT_NEAR(std::get<double>(var->function(p0)), 0., 1e-6);
976
977 var = Manager::Instance().getVariable("useTagSideRecoilRestFrame(daughter(1, pz), 0)");
978 ASSERT_NE(var, nullptr);
979 EXPECT_NEAR(std::get<double>(var->function(p0)), 0., 1e-6);
980
981 var = Manager::Instance().getVariable("useTagSideRecoilRestFrame(daughter(1, E), 0)");
982 ASSERT_NE(var, nullptr);
983 EXPECT_NEAR(std::get<double>(var->function(p0)), p1->getMass(), 1e-6);
984 }
985
986 TEST_F(MetaVariableTest, useMCancestorBRestFrame)
987 {
989 StoreArray<Particle> particles;
990 StoreArray<MCParticle> mcparticles;
991 particles.registerInDataStore();
992 mcparticles.registerInDataStore();
993 particles.registerRelationTo(mcparticles);
994 MCParticleGraph mcGraph;
995 // MC mother of the MC particle
996 MCParticleGraph::GraphParticle& mcMother = mcGraph.addParticle();
997 // MC particle of the reconstructed one
998 MCParticleGraph::GraphParticle& mcParticle = mcGraph.addParticle();
999 mcParticle.comesFrom(mcMother);
1000 mcGraph.generateList();
1001 // Reconstructed particle
1002 Particle particle({ 0.1, -0.4, 0.8, 1.0 }, 411);
1003 auto* p = particles.appendNew(particle);
1004 p->setVertex(XYZVector(1.0, 2.0, 2.0));
1005 p->addRelationTo(mcparticles[1]);
1006
1007 mcparticles[1]->setPDG(411);
1008
1009 // MC mother of the MC particle
1010 mcparticles[0]->setMomentum(XYZVector(0.0, 0.0, 0.1));
1011 mcparticles[0]->setStatus(MCParticle::c_PrimaryParticle);
1012 mcparticles[0]->setPDG(511);
1013 mcparticles[0]->setMassFromPDG();
1015
1016 const Manager::Var* var = Manager::Instance().getVariable("useMCancestorBRestFrame(p)");
1017 ASSERT_NE(var, nullptr);
1018 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0.88333338);
1019
1020 var = Manager::Instance().getVariable("useMCancestorBRestFrame(E)");
1021 ASSERT_NE(var, nullptr);
1022 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0.98502684);
1023
1024 var = Manager::Instance().getVariable("useMCancestorBRestFrame(distance)");
1025 ASSERT_NE(var, nullptr);
1026 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 3.0007174);
1027 }
1028
1029 TEST_F(MetaVariableTest, extraInfo)
1030 {
1031 Particle p({ 0.1, -0.4, 0.8, 1.0 }, 11);
1032 p.addExtraInfo("pi", 3.14);
1033
1034 const Manager::Var* var = Manager::Instance().getVariable("extraInfo(pi)");
1035 ASSERT_NE(var, nullptr);
1036 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 3.14);
1037
1038 // If nullptr is given, NaN is returned
1039 EXPECT_TRUE(std::isnan(std::get<double>(var->function(nullptr))));
1040 }
1041
1042 TEST_F(MetaVariableTest, eventExtraInfo)
1043 {
1044 StoreObjPtr<EventExtraInfo> eventExtraInfo;
1045 if (not eventExtraInfo.isValid())
1046 eventExtraInfo.create();
1047 eventExtraInfo->addExtraInfo("pi", 3.14);
1048 const Manager::Var* var = Manager::Instance().getVariable("eventExtraInfo(pi)");
1049 ASSERT_NE(var, nullptr);
1050 EXPECT_FLOAT_EQ(std::get<double>(var->function(nullptr)), 3.14);
1051 }
1052
1053 TEST_F(MetaVariableTest, eventCached)
1054 {
1055 const Manager::Var* var = Manager::Instance().getVariable("eventCached(constant(3.14))");
1056 ASSERT_NE(var, nullptr);
1057 EXPECT_FLOAT_EQ(std::get<double>(var->function(nullptr)), 3.14);
1058 StoreObjPtr<EventExtraInfo> eventExtraInfo;
1059 EXPECT_TRUE(eventExtraInfo.isValid());
1060 EXPECT_TRUE(eventExtraInfo->hasExtraInfo("__constant__bo3__pt14__bc"));
1061 EXPECT_FLOAT_EQ(eventExtraInfo->getExtraInfo("__constant__bo3__pt14__bc"), 3.14);
1062 eventExtraInfo->addExtraInfo("__eventExtraInfo__bopi__bc", 3.14);
1063 var = Manager::Instance().getVariable("eventCached(eventExtraInfo(pi))");
1064 ASSERT_NE(var, nullptr);
1065 EXPECT_FLOAT_EQ(std::get<double>(var->function(nullptr)), 3.14);
1066 }
1067
1068 TEST_F(MetaVariableTest, particleCached)
1069 {
1070 Particle p({ 0.1, -0.4, 0.8, 2.0 }, 11);
1071 const Manager::Var* var = Manager::Instance().getVariable("particleCached(px)");
1072 ASSERT_NE(var, nullptr);
1073 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.1);
1074 EXPECT_TRUE(p.hasExtraInfo("__px"));
1075 EXPECT_FLOAT_EQ(p.getExtraInfo("__px"), 0.1);
1076 p.addExtraInfo("__py", -0.5); // NOT -0.4 because we want to see if the cache is used instead of py!
1077 var = Manager::Instance().getVariable("particleCached(py)");
1078 ASSERT_NE(var, nullptr);
1079 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -0.5);
1080 }
1081
1082 TEST_F(MetaVariableTest, basicMathTest)
1083 {
1084 Particle p({ 0.1, -0.4, 0.8, 2.0 }, 411);
1085
1086 const Manager::Var* var = Manager::Instance().getVariable("abs(py)");
1087 ASSERT_NE(var, nullptr);
1088 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.4);
1089
1090 var = Manager::Instance().getVariable("min(E, pz)");
1091 ASSERT_NE(var, nullptr);
1092 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.8);
1093
1094 var = Manager::Instance().getVariable("max(E, pz)");
1095 ASSERT_NE(var, nullptr);
1096 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 2.0);
1097
1098 var = Manager::Instance().getVariable("log10(px)");
1099 ASSERT_NE(var, nullptr);
1100 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -1.0);
1101
1102 // sin 30 = 0.5
1103 var = Manager::Instance().getVariable("sin(0.5235987755983)");
1104 ASSERT_NE(var, nullptr);
1105 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.5);
1106
1107 // sin 90 = 1
1108 var = Manager::Instance().getVariable("sin(1.5707963267948966)");
1109 ASSERT_NE(var, nullptr);
1110 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.0);
1111
1112 // asin 1 = 90
1113 var = Manager::Instance().getVariable("asin(1.0)");
1114 ASSERT_NE(var, nullptr);
1115 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.5707963267948966);
1116
1117 // cos 60 = 0.5
1118 var = Manager::Instance().getVariable("cos(1.0471975511965976)");
1119 ASSERT_NE(var, nullptr);
1120 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.5);
1121
1122 // acos 0 = 90
1123 var = Manager::Instance().getVariable("acos(0)");
1124 ASSERT_NE(var, nullptr);
1125 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.5707963267948966);
1126
1127 }
1128
1129 TEST_F(MetaVariableTest, formula)
1130 {
1131 // see also unit tests in framework/formula_parser.cc
1132 //
1133 // keep particle-based tests here, and operator precedence tests (etc) in
1134 // framework with the parser itself
1135
1136 Particle p({ 0.1, -0.4, 0.8, 2.0 }, -411);
1137
1138 const Manager::Var* var = Manager::Instance().getVariable("formula(px + py)");
1139 ASSERT_NE(var, nullptr);
1140 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -0.3);
1141
1142 var = Manager::Instance().getVariable("formula(px - py)");
1143 ASSERT_NE(var, nullptr);
1144 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.5);
1145
1146 var = Manager::Instance().getVariable("formula(px * py)");
1147 ASSERT_NE(var, nullptr);
1148 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -0.04);
1149
1150 var = Manager::Instance().getVariable("formula(py / px)");
1151 ASSERT_NE(var, nullptr);
1152 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -4.0);
1153
1154 var = Manager::Instance().getVariable("formula(px ^ E)");
1155 ASSERT_NE(var, nullptr);
1156 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.01);
1157
1158 var = Manager::Instance().getVariable("formula(px * py + pz)");
1159 ASSERT_NE(var, nullptr);
1160 EXPECT_NEAR(std::get<double>(var->function(&p)), 0.76, 1e-6);
1161
1162 var = Manager::Instance().getVariable("formula(pz + px * py)");
1163 ASSERT_NE(var, nullptr);
1164 EXPECT_NEAR(std::get<double>(var->function(&p)), 0.76, 1e-6);
1165
1166 var = Manager::Instance().getVariable("formula(pt)");
1167 ASSERT_NE(var, nullptr);
1168 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.41231057);
1169 double pt = std::get<double>(var->function(&p));
1170
1171 var = Manager::Instance().getVariable("formula((px**2 + py**2)**(1/2))");
1172 ASSERT_NE(var, nullptr);
1173 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), pt);
1174
1175 var = Manager::Instance().getVariable("formula(charge)");
1176 ASSERT_NE(var, nullptr);
1177 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -1.0);
1178
1179 var = Manager::Instance().getVariable("formula(charge**2)");
1180 ASSERT_NE(var, nullptr);
1181 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.0);
1182
1183 var = Manager::Instance().getVariable("formula(charge^2)");
1184 ASSERT_NE(var, nullptr);
1185 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.0);
1186
1187 var = Manager::Instance().getVariable("formula(PDG * charge)");
1188 ASSERT_NE(var, nullptr);
1189 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 411.0);
1190
1191 var = Manager::Instance().getVariable("formula(PDG**2 * charge)");
1192 ASSERT_NE(var, nullptr);
1193 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -168921.0);
1194
1195 var = Manager::Instance().getVariable("formula(10.58 - (px + py + pz - E)**2)");
1196 ASSERT_NE(var, nullptr);
1197 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 8.33);
1198
1199 var = Manager::Instance().getVariable("formula(-10.58 + (px + py + pz - E)**2)");
1200 ASSERT_NE(var, nullptr);
1201 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -8.33);
1202
1203 var = Manager::Instance().getVariable("formula(-1.0 * PDG)");
1204 ASSERT_NE(var, nullptr);
1205 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 411);
1206 }
1207
1208 TEST_F(MetaVariableTest, passesCut)
1209 {
1210 Particle p({ 0.1, -0.4, 0.8, 2.0 }, 411);
1211 Particle p2({ 0.1, -0.4, 0.8, 4.0 }, 411);
1212
1213 const Manager::Var* var = Manager::Instance().getVariable("passesCut(E < 3)");
1214 ASSERT_NE(var, nullptr);
1215 EXPECT_TRUE(std::get<bool>(var->function(&p)));
1216 EXPECT_FALSE(std::get<bool>(var->function(&p2)));
1217 // EXPECT_TRUE(std::isnan(std::get<double>(var->function(nullptr)))); // Check that particle is present has been removed to allow change to bool as return type
1218
1219 }
1220
1221 TEST_F(MetaVariableTest, unmask)
1222 {
1224 StoreArray<MCParticle> mcParticles;
1225 StoreArray<Particle> particles;
1226 particles.registerInDataStore();
1227 mcParticles.registerInDataStore();
1228 particles.registerRelationTo(mcParticles);
1230
1231 // Create MC graph for B -> (muon -> electron + muon_neutrino) + anti_muon_neutrino
1232 MCParticleGraph mcGraph;
1233
1234 MCParticleGraph::GraphParticle& graphParticleGrandMother = mcGraph.addParticle();
1235
1236 MCParticleGraph::GraphParticle& graphParticleMother = mcGraph.addParticle();
1237 MCParticleGraph::GraphParticle& graphParticleAunt = mcGraph.addParticle();
1238
1239 MCParticleGraph::GraphParticle& graphParticleDaughter1 = mcGraph.addParticle();
1240 MCParticleGraph::GraphParticle& graphParticleDaughter2 = mcGraph.addParticle();
1241
1242 graphParticleGrandMother.setPDG(-521);
1243 graphParticleMother.setPDG(Const::muon.getPDGCode());
1244 graphParticleAunt.setPDG(-14);
1245 graphParticleDaughter1.setPDG(Const::electron.getPDGCode());
1246 graphParticleDaughter2.setPDG(14);
1247
1248 graphParticleMother.comesFrom(graphParticleGrandMother);
1249 graphParticleAunt.comesFrom(graphParticleGrandMother);
1250 graphParticleDaughter1.comesFrom(graphParticleMother);
1251 graphParticleDaughter2.comesFrom(graphParticleMother);
1252 mcGraph.generateList();
1253
1254
1255 // Get MC Particles from StoreArray
1256 auto* mcGrandMother = mcParticles[0];
1257 mcGrandMother->setStatus(MCParticle::c_PrimaryParticle);
1258
1259 auto* mcMother = mcParticles[1];
1260 mcMother->setStatus(MCParticle::c_PrimaryParticle);
1261
1262 auto* mcAunt = mcParticles[2];
1263 mcAunt->setStatus(MCParticle::c_PrimaryParticle);
1264
1265 auto* mcDaughter1 = mcParticles[3];
1266 mcDaughter1->setStatus(MCParticle::c_PrimaryParticle);
1267
1268 auto* mcDaughter2 = mcParticles[4];
1269 mcDaughter2->setStatus(MCParticle::c_PrimaryParticle);
1270
1271 auto* pGrandMother = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), -521);
1272 pGrandMother->addRelationTo(mcGrandMother);
1273
1274 auto* pMother = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 13);
1275 pMother->addRelationTo(mcMother);
1276
1277
1278 pMother->writeExtraInfo("mcErrors", 8);
1279 pGrandMother->writeExtraInfo("mcErrors", 8 | 16);
1280 const Manager::Var* var1 = Manager::Instance().getVariable("unmask(mcErrors, 8)");
1281 const Manager::Var* var2 = Manager::Instance().getVariable("unmask(mcErrors, 8, 16, 32, 64)");
1282 ASSERT_NE(var1, nullptr);
1283 EXPECT_FLOAT_EQ(std::get<double>(var1->function(pMother)), 0);
1284 EXPECT_FLOAT_EQ(std::get<double>(var1->function(pGrandMother)), 16);
1285 ASSERT_NE(var2, nullptr);
1286 EXPECT_FLOAT_EQ(std::get<double>(var2->function(pMother)), 0);
1287 EXPECT_FLOAT_EQ(std::get<double>(var2->function(pGrandMother)), 0);
1288
1289
1290 pMother->writeExtraInfo("mcErrors", 8 | 128);
1291 pGrandMother->writeExtraInfo("mcErrors", 8 | 16 | 512);
1292 ASSERT_NE(var1, nullptr);
1293 EXPECT_FLOAT_EQ(std::get<double>(var1->function(pMother)), 128);
1294 EXPECT_FLOAT_EQ(std::get<double>(var1->function(pGrandMother)), 16 | 512);
1295 ASSERT_NE(var2, nullptr);
1296 EXPECT_FLOAT_EQ(std::get<double>(var2->function(pMother)), 128);
1297 EXPECT_FLOAT_EQ(std::get<double>(var2->function(pGrandMother)), 512);
1298
1299 // unmask variable needs at least two arguments
1300 EXPECT_B2FATAL(Manager::Instance().getVariable("unmask(mcErrors)"));
1301
1302 // all but the first argument have to be integers
1303 EXPECT_B2FATAL(Manager::Instance().getVariable("unmask(mcErrors, NOTINT)"));
1304 }
1305
1306 TEST_F(MetaVariableTest, conditionalVariableSelector)
1307 {
1308 Particle p({ 0.1, -0.4, 0.8, 2.0 }, 411);
1309
1310 const Manager::Var* var = Manager::Instance().getVariable("conditionalVariableSelector(E>1, px, py)");
1311 ASSERT_NE(var, nullptr);
1312 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.1);
1313
1314 var = Manager::Instance().getVariable("conditionalVariableSelector(E<1, px, py)");
1315 ASSERT_NE(var, nullptr);
1316 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -0.4);
1317
1318 }
1319
1320 TEST_F(MetaVariableTest, nCleanedTracks)
1321 {
1323 StoreArray<TrackFitResult> track_fit_results;
1324 StoreArray<Track> tracks;
1325 track_fit_results.registerInDataStore();
1326 tracks.registerInDataStore();
1328
1329 Particle p({ 0.1, -0.4, 0.8, 2.0 }, 11);
1330 Particle p2({ 0.1, -0.4, 0.8, 4.0 }, 11);
1331
1332 track_fit_results.appendNew(ROOT::Math::XYZVector(0.1, 0.1, 0.1), ROOT::Math::XYZVector(0.1, 0.0, 0.0),
1333 TMatrixDSym(6), 1, Const::pion, 0.01, 1.5, 0, 0, 0);
1334 track_fit_results.appendNew(ROOT::Math::XYZVector(0.1, 0.1, 0.1), ROOT::Math::XYZVector(0.15, 0.0, 0.0),
1335 TMatrixDSym(6), 1, Const::pion, 0.01, 1.5, 0, 0, 0);
1336 track_fit_results.appendNew(ROOT::Math::XYZVector(0.1, 0.1, 0.1), ROOT::Math::XYZVector(0.4, 0.0, 0.0),
1337 TMatrixDSym(6), 1, Const::pion, 0.01, 1.5, 0, 0, 0);
1338 track_fit_results.appendNew(ROOT::Math::XYZVector(0.1, 0.1, 0.1), ROOT::Math::XYZVector(0.6, 0.0, 0.0),
1339 TMatrixDSym(6), 1, Const::pion, 0.01, 1.5, 0, 0, 0);
1340
1341 tracks.appendNew()->setTrackFitResultIndex(Const::pion, 0);
1342 tracks.appendNew()->setTrackFitResultIndex(Const::pion, 1);
1343 tracks.appendNew()->setTrackFitResultIndex(Const::pion, 2);
1344 tracks.appendNew()->setTrackFitResultIndex(Const::pion, 3);
1345
1346 const Manager::Var* var1 = Manager::Instance().getVariable("nCleanedTracks(p > 0.5)");
1347 EXPECT_FLOAT_EQ(std::get<int>(var1->function(nullptr)), 1);
1348
1349 const Manager::Var* var2 = Manager::Instance().getVariable("nCleanedTracks(p > 0.2)");
1350 EXPECT_FLOAT_EQ(std::get<int>(var2->function(nullptr)), 2);
1351
1352 const Manager::Var* var3 = Manager::Instance().getVariable("nCleanedTracks()");
1353 EXPECT_FLOAT_EQ(std::get<int>(var3->function(nullptr)), 4);
1354
1355
1356 }
1357
1358 TEST_F(MetaVariableTest, NumberOfMCParticlesInEvent)
1359 {
1360 Particle p({ 0.1, -0.4, 0.8, 2.0 }, 11);
1361 Particle p2({ 0.1, -0.4, 0.8, 4.0 }, 11);
1362
1363 StoreArray<MCParticle> mcParticles;
1364 auto* mcParticle = mcParticles.appendNew();
1365 mcParticle->setPDG(Const::electron.getPDGCode());
1367 mcParticle = mcParticles.appendNew();
1368 mcParticle->setPDG(Const::photon.getPDGCode());
1370 mcParticle = mcParticles.appendNew();
1371 mcParticle->setPDG(-Const::electron.getPDGCode());
1373 mcParticle = mcParticles.appendNew();
1374 mcParticle->setPDG(Const::electron.getPDGCode());
1375
1376
1377 const Manager::Var* var = Manager::Instance().getVariable("NumberOfMCParticlesInEvent(11)");
1378 ASSERT_NE(var, nullptr);
1379 EXPECT_EQ(std::get<int>(var->function(nullptr)), 2);
1380
1381 }
1382
1383 TEST_F(MetaVariableTest, daughterInvM)
1384 {
1385 PxPyPzEVector momentum;
1386 const int nDaughters = 6;
1387 StoreArray<Particle> particles;
1388 std::vector<int> daughterIndices;
1389 for (int i = 0; i < nDaughters; i++) {
1390 Particle d(PxPyPzEVector(2, 2, 2, 4.0), (i % 2) ? 213 : -213);
1391 momentum += d.get4Vector();
1392 Particle* newDaughters = particles.appendNew(d);
1393 daughterIndices.push_back(newDaughters->getArrayIndex());
1394 }
1395 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1396
1397 const Manager::Var* var = Manager::Instance().getVariable("daughterInvM(6,5)");
1398 ASSERT_NE(var, nullptr);
1399 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
1400
1401 var = Manager::Instance().getVariable("daughterInvM(0, 1)");
1402 ASSERT_NE(var, nullptr);
1403 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 4.0);
1404
1405 var = Manager::Instance().getVariable("daughterInvM(0, 1, 2)");
1406 ASSERT_NE(var, nullptr);
1407 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 6.0);
1408 }
1409
1410 TEST_F(MetaVariableTest, daughter)
1411 {
1412 PxPyPzEVector momentum;
1413 const int nDaughters = 6;
1414 StoreArray<Particle> particles;
1415 std::vector<int> daughterIndices;
1416 for (int i = 0; i < nDaughters; i++) {
1417 Particle d(PxPyPzEVector(i * 1.0, 1, 1, 1), (i % 2) ? 211 : -211);
1418 momentum += d.get4Vector();
1419 Particle* newDaughters = particles.appendNew(d);
1420 daughterIndices.push_back(newDaughters->getArrayIndex());
1421 }
1422 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1423
1424 const Manager::Var* var = Manager::Instance().getVariable("daughter(6, px)");
1425 ASSERT_NE(var, nullptr);
1426 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
1427
1428 var = Manager::Instance().getVariable("daughter(0, px)");
1429 ASSERT_NE(var, nullptr);
1430 EXPECT_NEAR(std::get<double>(var->function(p)), 0.0, 1e-6);
1431
1432 var = Manager::Instance().getVariable("daughter(1, px)");
1433 ASSERT_NE(var, nullptr);
1434 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 1.0);
1435
1436 var = Manager::Instance().getVariable("daughter(2, px)");
1437 ASSERT_NE(var, nullptr);
1438 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 2.0);
1439 }
1440
1441 TEST_F(MetaVariableTest, mcDaughter)
1442 {
1444 StoreArray<MCParticle> mcParticles;
1445 StoreArray<Particle> particles;
1446 particles.registerInDataStore();
1447 mcParticles.registerInDataStore();
1448 particles.registerRelationTo(mcParticles);
1450
1451 // Create MC graph for B -> (muon -> electron + muon_neutrino) + anti_muon_neutrino
1452 MCParticleGraph mcGraph;
1453
1454 MCParticleGraph::GraphParticle& graphParticleGrandMother = mcGraph.addParticle();
1455
1456 MCParticleGraph::GraphParticle& graphParticleMother = mcGraph.addParticle();
1457 MCParticleGraph::GraphParticle& graphParticleAunt = mcGraph.addParticle();
1458
1459 MCParticleGraph::GraphParticle& graphParticleDaughter1 = mcGraph.addParticle();
1460 MCParticleGraph::GraphParticle& graphParticleDaughter2 = mcGraph.addParticle();
1461
1462 graphParticleGrandMother.setPDG(-521);
1463 graphParticleMother.setPDG(Const::muon.getPDGCode());
1464 graphParticleAunt.setPDG(-14);
1465 graphParticleDaughter1.setPDG(Const::electron.getPDGCode());
1466 graphParticleDaughter2.setPDG(14);
1467
1468 graphParticleMother.comesFrom(graphParticleGrandMother);
1469 graphParticleAunt.comesFrom(graphParticleGrandMother);
1470 graphParticleDaughter1.comesFrom(graphParticleMother);
1471 graphParticleDaughter2.comesFrom(graphParticleMother);
1472 mcGraph.generateList();
1473
1474 // Get MC Particles from StoreArray
1475 auto* mcGrandMother = mcParticles[0];
1476 mcGrandMother->setStatus(MCParticle::c_PrimaryParticle);
1477
1478 auto* mcMother = mcParticles[1];
1479 mcMother->setStatus(MCParticle::c_PrimaryParticle);
1480
1481 auto* mcAunt = mcParticles[2];
1482 mcAunt->setStatus(MCParticle::c_PrimaryParticle);
1483
1484 auto* mcDaughter1 = mcParticles[3];
1485 mcDaughter1->setStatus(MCParticle::c_PrimaryParticle);
1486
1487 auto* mcDaughter2 = mcParticles[4];
1488 mcDaughter2->setStatus(MCParticle::c_PrimaryParticle);
1489
1490 auto* pGrandMother = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), -521);
1491 pGrandMother->addRelationTo(mcGrandMother);
1492
1493 auto* pMother = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 13);
1494 pMother->addRelationTo(mcMother);
1495
1496 // Test for particle that has no MC match
1497 auto* p_noMC = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 13);
1498
1499 // Test for particle that has MC match, but MC match has no daughter
1500 auto* p_noDaughter = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
1501 p_noDaughter->addRelationTo(mcDaughter1);
1502
1503 const Manager::Var* var = Manager::Instance().getVariable("mcDaughter(0, PDG)");
1504 ASSERT_NE(var, nullptr);
1505 EXPECT_FLOAT_EQ(std::get<double>(var->function(pGrandMother)), 13);
1506 EXPECT_FLOAT_EQ(std::get<double>(var->function(pMother)), 11);
1507 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p_noMC))));
1508 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p_noDaughter))));
1509 var = Manager::Instance().getVariable("mcDaughter(1, PDG)");
1510 EXPECT_FLOAT_EQ(std::get<double>(var->function(pGrandMother)), -14);
1511 EXPECT_FLOAT_EQ(std::get<double>(var->function(pMother)), 14);
1512 // Test for particle where mc daughter index is out of range of mc daughters
1513 var = Manager::Instance().getVariable("mcDaughter(2, PDG)");
1514 EXPECT_TRUE(std::isnan(std::get<double>(var->function(pGrandMother))));
1515 EXPECT_TRUE(std::isnan(std::get<double>(var->function(pMother))));
1516 // Test nested application of mcDaughter
1517 var = Manager::Instance().getVariable("mcDaughter(0, mcDaughter(0, PDG))");
1518 EXPECT_FLOAT_EQ(std::get<double>(var->function(pGrandMother)), 11);
1519 EXPECT_TRUE(std::isnan(std::get<double>(var->function(pMother))));
1520 var = Manager::Instance().getVariable("mcDaughter(0, mcDaughter(1, PDG))");
1521 EXPECT_FLOAT_EQ(std::get<double>(var->function(pGrandMother)), 14);
1522 var = Manager::Instance().getVariable("mcDaughter(0, mcDaughter(2, PDG))");
1523 EXPECT_TRUE(std::isnan(std::get<double>(var->function(pGrandMother))));
1524 var = Manager::Instance().getVariable("mcDaughter(1, mcDaughter(0, PDG))");
1525 EXPECT_TRUE(std::isnan(std::get<double>(var->function(pGrandMother))));
1526 }
1527
1528 TEST_F(MetaVariableTest, mcMother)
1529 {
1531 StoreArray<MCParticle> mcParticles;
1532 StoreArray<Particle> particles;
1533 particles.registerInDataStore();
1534 mcParticles.registerInDataStore();
1535 particles.registerRelationTo(mcParticles);
1537
1538 // Create MC graph for B -> (muon -> electron + muon_neutrino) + anti_muon_neutrino
1539 MCParticleGraph mcGraph;
1540
1541 MCParticleGraph::GraphParticle& graphParticleGrandMother = mcGraph.addParticle();
1542
1543 MCParticleGraph::GraphParticle& graphParticleMother = mcGraph.addParticle();
1544 MCParticleGraph::GraphParticle& graphParticleAunt = mcGraph.addParticle();
1545
1546 MCParticleGraph::GraphParticle& graphParticleDaughter1 = mcGraph.addParticle();
1547 MCParticleGraph::GraphParticle& graphParticleDaughter2 = mcGraph.addParticle();
1548
1549 graphParticleGrandMother.setPDG(-521);
1550 graphParticleMother.setPDG(Const::muon.getPDGCode());
1551 graphParticleAunt.setPDG(-14);
1552 graphParticleDaughter1.setPDG(Const::electron.getPDGCode());
1553 graphParticleDaughter2.setPDG(14);
1554
1555 graphParticleMother.comesFrom(graphParticleGrandMother);
1556 graphParticleAunt.comesFrom(graphParticleGrandMother);
1557 graphParticleDaughter1.comesFrom(graphParticleMother);
1558 graphParticleDaughter2.comesFrom(graphParticleMother);
1559
1560 mcGraph.generateList();
1561
1562 // Get MC Particles from StoreArray
1563 auto* mcGrandMother = mcParticles[0];
1564 mcGrandMother->setStatus(MCParticle::c_PrimaryParticle);
1565
1566 auto* mcMother = mcParticles[1];
1567 mcMother->setStatus(MCParticle::c_PrimaryParticle);
1568
1569 auto* mcAunt = mcParticles[2];
1570 mcAunt->setStatus(MCParticle::c_PrimaryParticle);
1571
1572 auto* mcDaughter1 = mcParticles[3];
1573 mcDaughter1->setStatus(MCParticle::c_PrimaryParticle);
1574
1575 auto* mcDaughter2 = mcParticles[4];
1576 mcDaughter2->setStatus(MCParticle::c_PrimaryParticle);
1577
1578 auto* p1 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
1579 p1->addRelationTo(mcDaughter1);
1580
1581 auto* p2 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 14);
1582 p2->addRelationTo(mcDaughter2);
1583
1584 auto* pMother = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 13);
1585 pMother->addRelationTo(mcMother);
1586
1587 // For test of particle that has no MC match
1588 auto* p_noMC = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
1589
1590 // For test of particle that has MC match, but MC match has no mother
1591 auto* p_noMother = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), -521);
1592 p_noMother->addRelationTo(mcGrandMother);
1593
1594 const Manager::Var* var = Manager::Instance().getVariable("mcMother(PDG)");
1595 ASSERT_NE(var, nullptr);
1596 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), 13);
1597 EXPECT_FLOAT_EQ(std::get<double>(var->function(p2)), 13);
1598 EXPECT_FLOAT_EQ(std::get<double>(var->function(pMother)), -521);
1599 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p_noMC))));
1600 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p_noMother))));
1601
1602 // Test if nested calls of mcMother work correctly
1603 var = Manager::Instance().getVariable("mcMother(mcMother(PDG))");
1604 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), -521);
1605 }
1606
1607 TEST_F(MetaVariableTest, genParticle)
1608 {
1610 StoreArray<MCParticle> mcParticles;
1611 StoreArray<Particle> particles;
1612 particles.registerInDataStore();
1613 mcParticles.registerInDataStore();
1614 particles.registerRelationTo(mcParticles);
1616
1617 // Create MC graph for Upsilon(4S) -> (B^- -> electron + anti_electron_neutrino) + B^+
1618 MCParticleGraph mcGraph;
1619
1620 MCParticleGraph::GraphParticle& graphParticleGrandMother = mcGraph.addParticle();
1621
1622 MCParticleGraph::GraphParticle& graphParticleMother = mcGraph.addParticle();
1623 MCParticleGraph::GraphParticle& graphParticleAunt = mcGraph.addParticle();
1624
1625 MCParticleGraph::GraphParticle& graphParticleDaughter1 = mcGraph.addParticle();
1626 MCParticleGraph::GraphParticle& graphParticleDaughter2 = mcGraph.addParticle();
1627
1628 graphParticleGrandMother.setPDG(300553);
1629 graphParticleMother.setPDG(-521);
1630 graphParticleAunt.setPDG(521);
1631 graphParticleDaughter1.setPDG(Const::electron.getPDGCode());
1632 graphParticleDaughter2.setPDG(-12);
1633
1634 graphParticleGrandMother.setMomentum(0.0, 0.0, 0.4);
1635 graphParticleMother.setMomentum(1.1, 1.3, 1.5);
1636
1637 graphParticleMother.comesFrom(graphParticleGrandMother);
1638 graphParticleAunt.comesFrom(graphParticleGrandMother);
1639 graphParticleDaughter1.comesFrom(graphParticleMother);
1640 graphParticleDaughter2.comesFrom(graphParticleMother);
1641
1642 mcGraph.generateList();
1643
1644 // Get MC Particles from StoreArray
1645 auto* mcGrandMother = mcParticles[0];
1646 mcGrandMother->setStatus(MCParticle::c_PrimaryParticle);
1647
1648 auto* mcMother = mcParticles[1];
1649 mcMother->setStatus(MCParticle::c_PrimaryParticle);
1650
1651 auto* mcAunt = mcParticles[2];
1652 mcAunt->setStatus(MCParticle::c_PrimaryParticle);
1653
1654 auto* mcDaughter1 = mcParticles[3];
1655 mcDaughter1->setStatus(MCParticle::c_PrimaryParticle);
1656
1657 auto* mcDaughter2 = mcParticles[4];
1658 mcDaughter2->setStatus(MCParticle::c_PrimaryParticle);
1659
1660 auto* p1 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
1661 p1->addRelationTo(mcDaughter1);
1662
1663 // For test of particle that has no MC match
1664 auto* p_noMC = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 211);
1665
1666 const Manager::Var* var = Manager::Instance().getVariable("genParticle(0, PDG)");
1667 ASSERT_NE(var, nullptr);
1668 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), 300553);
1669 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), 300553);
1670
1671 var = Manager::Instance().getVariable("genParticle(0, matchedMC(pz))");
1672 ASSERT_NE(var, nullptr);
1673 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), 0.4);
1674 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), 0.4);
1675
1676 var = Manager::Instance().getVariable("genParticle(0, mcDaughter(0, PDG))");
1677 ASSERT_NE(var, nullptr);
1678 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), -521);
1679 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), -521);
1680
1681 var = Manager::Instance().getVariable("genParticle(0, mcDaughter(0, matchedMC(px)))");
1682 ASSERT_NE(var, nullptr);
1683 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), 1.1);
1684 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), 1.1);
1685
1686 var = Manager::Instance().getVariable("genParticle(1, PDG)");
1687 ASSERT_NE(var, nullptr);
1688 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), -521);
1689 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), -521);
1690
1691 var = Manager::Instance().getVariable("genParticle(4, PDG)");
1692 ASSERT_NE(var, nullptr);
1693 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), -12);
1694 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), -12);
1695
1696 var = Manager::Instance().getVariable("genParticle(5, PDG)");
1697 ASSERT_NE(var, nullptr);
1698 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p1))));
1699 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p_noMC))));
1700 }
1701
1702 TEST_F(MetaVariableTest, genUpsilon4S)
1703 {
1705 StoreArray<MCParticle> mcParticles;
1706 StoreArray<Particle> particles;
1707 particles.registerInDataStore();
1708 mcParticles.registerInDataStore();
1709 particles.registerRelationTo(mcParticles);
1711
1712 // Create MC graph for Upsilon(4S) -> (B^- -> electron + anti_electron_neutrino) + B^+
1713 MCParticleGraph mcGraph;
1714
1715 MCParticleGraph::GraphParticle& graphParticleGrandMother = mcGraph.addParticle();
1716
1717 MCParticleGraph::GraphParticle& graphParticleMother = mcGraph.addParticle();
1718 MCParticleGraph::GraphParticle& graphParticleAunt = mcGraph.addParticle();
1719
1720 MCParticleGraph::GraphParticle& graphParticleDaughter1 = mcGraph.addParticle();
1721 MCParticleGraph::GraphParticle& graphParticleDaughter2 = mcGraph.addParticle();
1722
1723 graphParticleGrandMother.setPDG(300553);
1724 graphParticleMother.setPDG(-521);
1725 graphParticleAunt.setPDG(521);
1726 graphParticleDaughter1.setPDG(Const::electron.getPDGCode());
1727 graphParticleDaughter2.setPDG(-12);
1728
1729 graphParticleGrandMother.setMomentum(0.0, 0.0, 0.4);
1730 graphParticleMother.setMomentum(1.1, 1.3, 1.5);
1731
1732 graphParticleMother.comesFrom(graphParticleGrandMother);
1733 graphParticleAunt.comesFrom(graphParticleGrandMother);
1734 graphParticleDaughter1.comesFrom(graphParticleMother);
1735 graphParticleDaughter2.comesFrom(graphParticleMother);
1736
1737 mcGraph.generateList();
1738
1739 // Get MC Particles from StoreArray
1740 auto* mcGrandMother = mcParticles[0];
1741 mcGrandMother->setStatus(MCParticle::c_PrimaryParticle);
1742
1743 auto* mcMother = mcParticles[1];
1744 mcMother->setStatus(MCParticle::c_PrimaryParticle);
1745
1746 auto* mcAunt = mcParticles[2];
1747 mcAunt->setStatus(MCParticle::c_PrimaryParticle);
1748
1749 auto* mcDaughter1 = mcParticles[3];
1750 mcDaughter1->setStatus(MCParticle::c_PrimaryParticle);
1751
1752 auto* mcDaughter2 = mcParticles[4];
1753 mcDaughter2->setStatus(MCParticle::c_PrimaryParticle);
1754
1755 auto* p1 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
1756 p1->addRelationTo(mcDaughter1);
1757
1758 // For test of particle that has no MC match
1759 auto* p_noMC = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 211);
1760
1761 const Manager::Var* var = Manager::Instance().getVariable("genUpsilon4S(PDG)");
1762 ASSERT_NE(var, nullptr);
1763 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), 300553);
1764 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), 300553);
1765
1766 var = Manager::Instance().getVariable("genUpsilon4S(matchedMC(pz))");
1767 ASSERT_NE(var, nullptr);
1768 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), 0.4);
1769 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), 0.4);
1770
1771 var = Manager::Instance().getVariable("genUpsilon4S(mcDaughter(0, PDG))");
1772 ASSERT_NE(var, nullptr);
1773 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), -521);
1774 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), -521);
1775
1776 var = Manager::Instance().getVariable("genUpsilon4S(mcDaughter(0, matchedMC(px)))");
1777 ASSERT_NE(var, nullptr);
1778 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), 1.1);
1779 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), 1.1);
1780
1782 mcParticles.clear();
1783 particles.clear();
1784 MCParticleGraph mcGraph2;
1785
1786 MCParticleGraph::GraphParticle& graphParticle1 = mcGraph2.addParticle();
1787 MCParticleGraph::GraphParticle& graphParticle2 = mcGraph2.addParticle();
1788
1789 graphParticle1.setPDG(Const::electron.getPDGCode());
1790 graphParticle2.setPDG(-Const::electron.getPDGCode());
1791
1792 graphParticle1.setMomentum(1.1, 1.3, 1.4);
1793 graphParticle1.setMomentum(-1.1, -1.3, 1.4);
1794
1795 mcGraph2.generateList();
1796
1797 auto* mcP1 = mcParticles[0];
1798 mcP1->setStatus(MCParticle::c_PrimaryParticle);
1799
1800 auto* mcP2 = mcParticles[1];
1801 mcP2->setStatus(MCParticle::c_PrimaryParticle);
1802
1803 auto* someParticle = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
1804 someParticle->addRelationTo(mcP1);
1805
1806 var = Manager::Instance().getVariable("genUpsilon4S(PDG)");
1807 ASSERT_NE(var, nullptr);
1808 EXPECT_TRUE(std::isnan(std::get<double>(var->function(someParticle))));
1809 }
1810
1811 TEST_F(MetaVariableTest, daughterProductOf)
1812 {
1813 PxPyPzEVector momentum;
1814 const int nDaughters = 4;
1815 StoreArray<Particle> particles;
1816 std::vector<int> daughterIndices;
1817 for (int i = 0; i < nDaughters; i++) {
1818 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 2.0), (i % 2) ? 213 : -213);
1819 momentum += d.get4Vector();
1820 Particle* newDaughters = particles.appendNew(d);
1821 daughterIndices.push_back(newDaughters->getArrayIndex());
1822 }
1823 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1824
1825 const Manager::Var* var = Manager::Instance().getVariable("daughterProductOf(E)");
1826 ASSERT_NE(var, nullptr);
1827 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 120.0);
1828 }
1829
1830 TEST_F(MetaVariableTest, daughterSumOf)
1831 {
1832 PxPyPzEVector momentum;
1833 const int nDaughters = 4;
1834 StoreArray<Particle> particles;
1835 std::vector<int> daughterIndices;
1836 for (int i = 0; i < nDaughters; i++) {
1837 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 2.0), (i % 2) ? 213 : -213);
1838 momentum += d.get4Vector();
1839 Particle* newDaughters = particles.appendNew(d);
1840 daughterIndices.push_back(newDaughters->getArrayIndex());
1841 }
1842 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1843
1844 const Manager::Var* var = Manager::Instance().getVariable("daughterSumOf(E)");
1845 ASSERT_NE(var, nullptr);
1846 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 14.0);
1847 }
1848
1849 TEST_F(MetaVariableTest, daughterLowest)
1850 {
1851 PxPyPzEVector momentum;
1852 const int nDaughters = 4;
1853 StoreArray<Particle> particles;
1854 std::vector<int> daughterIndices;
1855 for (int i = 0; i < nDaughters; i++) {
1856 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 2.0), (i % 2) ? 213 : -213);
1857 momentum += d.get4Vector();
1858 Particle* newDaughters = particles.appendNew(d);
1859 daughterIndices.push_back(newDaughters->getArrayIndex());
1860 }
1861 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1862
1863 const Manager::Var* var = Manager::Instance().getVariable("daughterLowest(E)");
1864 ASSERT_NE(var, nullptr);
1865 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 2.0);
1866 }
1867
1868 TEST_F(MetaVariableTest, daughterHighest)
1869 {
1870 PxPyPzEVector momentum;
1871 const int nDaughters = 4;
1872 StoreArray<Particle> particles;
1873 std::vector<int> daughterIndices;
1874 for (int i = 0; i < nDaughters; i++) {
1875 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 1.0), (i % 2) ? 213 : -213);
1876 momentum += d.get4Vector();
1877 Particle* newDaughters = particles.appendNew(d);
1878 daughterIndices.push_back(newDaughters->getArrayIndex());
1879 }
1880 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1881
1882 const Manager::Var* var = Manager::Instance().getVariable("daughterHighest(E)");
1883 ASSERT_NE(var, nullptr);
1884 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 4.0);
1885 }
1886
1887 TEST_F(MetaVariableTest, daughterDiffOf)
1888 {
1889 PxPyPzEVector momentum;
1890 const int nDaughters = 4;
1891 StoreArray<Particle> particles;
1892 std::vector<int> daughterIndices;
1893 for (int i = 0; i < nDaughters; i++) {
1894 Particle d(PxPyPzEVector(-1, 1.0 - 2 * (i % 2), 1, i * 1.0 + 2.0), (i % 2) ? -11 : 211);
1895 momentum += d.get4Vector();
1896 Particle* newDaughters = particles.appendNew(d);
1897 daughterIndices.push_back(newDaughters->getArrayIndex());
1898 }
1899 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1900
1901 const Manager::Var* var = Manager::Instance().getVariable("daughterDiffOf(0, 1, PDG)");
1902 ASSERT_NE(var, nullptr);
1903 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -222);
1904
1905 var = Manager::Instance().getVariable("daughterDiffOf(1, 0, PDG)");
1906 ASSERT_NE(var, nullptr);
1907 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 222);
1908
1909 var = Manager::Instance().getVariable("daughterDiffOf(0, 1, abs(PDG))");
1910 ASSERT_NE(var, nullptr);
1911 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -200);
1912
1913 var = Manager::Instance().getVariable("daughterDiffOf(1, 1, PDG)");
1914 ASSERT_NE(var, nullptr);
1915 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0);
1916
1917 var = Manager::Instance().getVariable("daughterDiffOf(1, 3, abs(PDG))");
1918 ASSERT_NE(var, nullptr);
1919 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0);
1920
1921 var = Manager::Instance().getVariable("daughterDiffOf(0, 2, PDG)");
1922 ASSERT_NE(var, nullptr);
1923 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0);
1924
1925 var = Manager::Instance().getVariable("daughterDiffOf(1, 0, phi)");
1926 ASSERT_NE(var, nullptr);
1927 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -1.5707964);
1928
1929 var = Manager::Instance().getVariable("daughterDiffOf(1, 0, useCMSFrame(phi))");
1930 ASSERT_NE(var, nullptr);
1931 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -1.5004894);
1932
1933 var = Manager::Instance().getVariable("daughterDiffOf(0, NOTINT, PDG)");
1934 ASSERT_NE(var, nullptr);
1935 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
1936 }
1937
1938
1939 TEST_F(MetaVariableTest, mcDaughterDiffOf)
1940 {
1942 PxPyPzEVector momentum;
1943 const int nDaughters = 4;
1944 StoreArray<Particle> particles;
1945 StoreArray<MCParticle> mcParticles;
1946 particles.registerRelationTo(mcParticles);
1947 std::vector<int> daughterIndices;
1949
1950 for (int i = 0; i < nDaughters; i++) {
1951 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 1.0), (i % 2) ? -11 : 211);
1952 momentum += d.get4Vector();
1953 Particle* newDaughters = particles.appendNew(d);
1954 daughterIndices.push_back(newDaughters->getArrayIndex());
1955 auto* mcParticle = mcParticles.appendNew();
1956 mcParticle->setPDG((i % 2) ? -Const::electron.getPDGCode() : Const::pion.getPDGCode());
1958 newDaughters->addRelationTo(mcParticle);
1959 }
1960 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1961
1962 const Manager::Var* var = Manager::Instance().getVariable("mcDaughterDiffOf(0, 1, PDG)");
1963 ASSERT_NE(var, nullptr);
1964 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -222);
1965
1966 var = Manager::Instance().getVariable("mcDaughterDiffOf(1, 0, PDG)");
1967 ASSERT_NE(var, nullptr);
1968 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 222);
1969
1970 var = Manager::Instance().getVariable("mcDaughterDiffOf(0, 1, abs(PDG))");
1971 ASSERT_NE(var, nullptr);
1972 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -200);
1973
1974 var = Manager::Instance().getVariable("mcDaughterDiffOf(1, 1, PDG)");
1975 ASSERT_NE(var, nullptr);
1976 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0);
1977
1978 var = Manager::Instance().getVariable("mcDaughterDiffOf(1, 3, abs(PDG))");
1979 ASSERT_NE(var, nullptr);
1980 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0);
1981
1982 var = Manager::Instance().getVariable("mcDaughterDiffOf(0, 2, PDG)");
1983 ASSERT_NE(var, nullptr);
1984 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0);
1985
1986 var = Manager::Instance().getVariable("mcDaughterDiffOf(0, NOTINT, PDG)");
1987 ASSERT_NE(var, nullptr);
1988 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
1989 }
1990
1991
1992
1993 TEST_F(MetaVariableTest, daughterClusterAngleInBetween)
1994 {
1995 // declare all the array we need
1996 StoreArray<Particle> particles;
1997 std::vector<int> daughterIndices, daughterIndices_noclst;
1998
1999 //proxy initialize where to declare the needed array
2001 StoreArray<ECLCluster> eclclusters;
2002 eclclusters.registerInDataStore();
2003 particles.registerRelationTo(eclclusters);
2005
2006 // create two Lorentz vectors that are back to back in the CMS and boost them to the Lab frame
2007 const float px_CM = 2.;
2008 const float py_CM = 1.;
2009 const float pz_CM = 3.;
2010 float E_CM;
2011 E_CM = sqrt(pow(px_CM, 2) + pow(py_CM, 2) + pow(pz_CM, 2));
2012 PxPyPzEVector momentum, momentum_noclst;
2013 PxPyPzEVector dau0_4vec_CM(px_CM, py_CM, pz_CM, E_CM), dau1_4vec_CM(-px_CM, -py_CM, -pz_CM, E_CM);
2014 PxPyPzEVector dau0_4vec_Lab, dau1_4vec_Lab;
2015 dau0_4vec_Lab = PCmsLabTransform::cmsToLab(
2016 dau0_4vec_CM); //why is everybody using the extended method when there are the functions that do all the steps for us?
2017 dau1_4vec_Lab = PCmsLabTransform::cmsToLab(dau1_4vec_CM);
2018
2019 // add the two photons (now in the Lab frame) as the two daughters of some particle and create the latter
2020 Particle dau0_noclst(dau0_4vec_Lab, 22);
2021 momentum += dau0_noclst.get4Vector();
2022 Particle* newDaughter0_noclst = particles.appendNew(dau0_noclst);
2023 daughterIndices_noclst.push_back(newDaughter0_noclst->getArrayIndex());
2024 Particle dau1_noclst(dau1_4vec_Lab, 22);
2025 momentum += dau1_noclst.get4Vector();
2026 Particle* newDaughter1_noclst = particles.appendNew(dau1_noclst);
2027 daughterIndices_noclst.push_back(newDaughter1_noclst->getArrayIndex());
2028 const Particle* par_noclst = particles.appendNew(momentum, 111, Particle::c_Unflavored, daughterIndices_noclst);
2029
2030 // grab variables
2031 const Manager::Var* var = Manager::Instance().getVariable("daughterClusterAngleInBetween(0, 1)");
2032 const Manager::Var* varCMS = Manager::Instance().getVariable("useCMSFrame(daughterClusterAngleInBetween(0, 1))");
2033
2034 // when no relations are set between the particles and the eclClusters, nan is expected to be returned
2035 ASSERT_NE(var, nullptr);
2036 EXPECT_TRUE(std::isnan(std::get<double>(var->function(par_noclst))));
2037
2038 // set relations between particles and eclClusters
2039 ECLCluster* eclst0 = eclclusters.appendNew(ECLCluster());
2040 eclst0->setEnergy(dau0_4vec_Lab.E());
2041 eclst0->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
2042 eclst0->setClusterId(1);
2043 eclst0->setTheta(dau0_4vec_Lab.Theta());
2044 eclst0->setPhi(dau0_4vec_Lab.Phi());
2045 eclst0->setR(148.4);
2046 ECLCluster* eclst1 = eclclusters.appendNew(ECLCluster());
2047 eclst1->setEnergy(dau1_4vec_Lab.E());
2048 eclst1->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
2049 eclst1->setClusterId(2);
2050 eclst1->setTheta(dau1_4vec_Lab.Theta());
2051 eclst1->setPhi(dau1_4vec_Lab.Phi());
2052 eclst1->setR(148.5);
2053
2054 const Particle* newDaughter0 = particles.appendNew(Particle(eclclusters[0]));
2055 daughterIndices.push_back(newDaughter0->getArrayIndex());
2056 const Particle* newDaughter1 = particles.appendNew(Particle(eclclusters[1]));
2057 daughterIndices.push_back(newDaughter1->getArrayIndex());
2058
2059 const Particle* par = particles.appendNew(momentum, 111, Particle::c_Unflavored, daughterIndices);
2060
2061 //now we expect non-nan results
2062 EXPECT_FLOAT_EQ(std::get<double>(var->function(par)), 2.8613892);
2063 EXPECT_FLOAT_EQ(std::get<double>(varCMS->function(par)), M_PI);
2064 }
2065
2066 TEST_F(MetaVariableTest, grandDaughterDiffOfs)
2067 {
2068 // declare all the array we need
2069 StoreArray<Particle> particles;
2070 std::vector<int> daughterIndices0_noclst, daughterIndices1_noclst, daughterIndices2_noclst;
2071 std::vector<int> daughterIndices0, daughterIndices1, daughterIndices2;
2072
2073 //proxy initialize where to declare the needed array
2075 StoreArray<ECLCluster> eclclusters;
2076 eclclusters.registerInDataStore();
2077 particles.registerRelationTo(eclclusters);
2079
2080 // create two Lorentz vectors
2081 const float px_0 = 2.;
2082 const float py_0 = 1.;
2083 const float pz_0 = 3.;
2084 const float px_1 = 1.5;
2085 const float py_1 = 1.5;
2086 const float pz_1 = 2.5;
2087 float E_0, E_1;
2088 E_0 = sqrt(pow(px_0, 2) + pow(py_0, 2) + pow(pz_0, 2));
2089 E_1 = sqrt(pow(px_1, 2) + pow(py_1, 2) + pow(pz_1, 2));
2090 PxPyPzEVector momentum_0, momentum_1, momentum;
2091 PxPyPzEVector dau0_4vec(px_0, py_0, pz_0, E_0), dau1_4vec(px_1, py_1, pz_1, E_1);
2092
2093 // add the two photons as the two daughters of some particle and create the latter
2094 // Particle dau0_noclst(dau0_4vec, 22);
2095 // momentum += dau0_noclst.get4Vector();
2096 // Particle* newDaughter0_noclst = particles.appendNew(dau0_noclst);
2097 // daughterIndices_noclst.push_back(newDaughter0_noclst->getArrayIndex());
2098 // Particle dau1_noclst(dau1_4vec, 22);
2099 // momentum += dau1_noclst.get4Vector();
2100 // Particle* newDaughter1_noclst = particles.appendNew(dau1_noclst);
2101 // daughterIndices_noclst.push_back(newDaughter1_noclst->getArrayIndex());
2102 // const Particle* par_noclst = particles.appendNew(momentum, 111, Particle::c_Unflavored, daughterIndices_noclst);
2103
2104 Particle dau0_noclst(dau0_4vec, 22);
2105 momentum_0 = dau0_4vec;
2106 Particle* newDaughter0_noclst = particles.appendNew(dau0_noclst);
2107 daughterIndices0_noclst.push_back(newDaughter0_noclst->getArrayIndex());
2108 const Particle* par0_noclst = particles.appendNew(momentum_0, 111, Particle::c_Unflavored, daughterIndices0_noclst);
2109 Particle dau1_noclst(dau1_4vec, 22);
2110 momentum_1 = dau1_4vec;
2111 Particle* newDaughter1_noclst = particles.appendNew(dau1_noclst);
2112 daughterIndices1_noclst.push_back(newDaughter1_noclst->getArrayIndex());
2113 const Particle* par1_noclst = particles.appendNew(momentum_1, 111, Particle::c_Unflavored, daughterIndices1_noclst);
2114
2115 momentum = momentum_0 + momentum_1;
2116 daughterIndices2_noclst.push_back(par0_noclst->getArrayIndex());
2117 daughterIndices2_noclst.push_back(par1_noclst->getArrayIndex());
2118 const Particle* parGranny_noclst = particles.appendNew(momentum, 111, Particle::c_Unflavored, daughterIndices2_noclst);
2119
2120 // grab variables
2121 const Manager::Var* var_Theta = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,0,0,theta)");
2122 const Manager::Var* var_ClusterTheta = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,0,0,clusterTheta)");
2123 const Manager::Var* var_E = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,0,0,E)");
2124 const Manager::Var* var_ClusterE = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,0,0,clusterE)");
2125 const Manager::Var* var_E_wrongIndexes = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,2,3,E)");
2126 const Manager::Var* var_ClusterE_wrongIndexes = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,2,3,clusterE)");
2127
2128 const Manager::Var* var_ClusterPhi = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,0,0,clusterPhi)");
2129 const Manager::Var* var_Phi = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,0,0,phi)");
2130 const Manager::Var* var_ClusterPhi_wrongIndexes = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,2,3,clusterPhi)");
2131 const Manager::Var* var_Phi_wrongIndexes = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,2,3,phi)");
2132
2133 // when no relations are set between the particles and the eclClusters, nan is expected to be returned for the Cluster- vars
2134 // no problems are supposed to happen for non-Cluster- vars
2135 // also, we expect NaN when we pass wrong indexes
2136 ASSERT_NE(var_ClusterPhi, nullptr);
2137 EXPECT_TRUE(std::isnan(std::get<double>(var_ClusterPhi->function(parGranny_noclst))));
2138 EXPECT_TRUE(std::isnan(std::get<double>(var_ClusterTheta->function(parGranny_noclst))));
2139 EXPECT_TRUE(std::isnan(std::get<double>(var_ClusterE->function(parGranny_noclst))));
2140 EXPECT_FLOAT_EQ(std::get<double>(var_Phi->function(parGranny_noclst)), 0.32175055);
2141 EXPECT_FLOAT_EQ(std::get<double>(var_Theta->function(parGranny_noclst)), 0.06311664);
2142 EXPECT_FLOAT_EQ(std::get<double>(var_E->function(parGranny_noclst)), -0.46293807);
2143 EXPECT_TRUE(std::isnan(std::get<double>(var_ClusterPhi_wrongIndexes->function(parGranny_noclst))));
2144 EXPECT_TRUE(std::isnan(std::get<double>(var_Phi_wrongIndexes->function(parGranny_noclst))));
2145 EXPECT_TRUE(std::isnan(std::get<double>(var_ClusterE_wrongIndexes->function(parGranny_noclst))));
2146 EXPECT_TRUE(std::isnan(std::get<double>(var_E_wrongIndexes->function(parGranny_noclst))));
2147
2148 // set relations between particles and eclClusters
2149 ECLCluster* eclst0 = eclclusters.appendNew(ECLCluster());
2150 eclst0->setEnergy(dau0_4vec.E());
2151 eclst0->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
2152 eclst0->setClusterId(1);
2153 eclst0->setTheta(dau0_4vec.Theta());
2154 eclst0->setPhi(dau0_4vec.Phi());
2155 eclst0->setR(148.4);
2156 ECLCluster* eclst1 = eclclusters.appendNew(ECLCluster());
2157 eclst1->setEnergy(dau1_4vec.E());
2158 eclst1->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
2159 eclst1->setClusterId(2);
2160 eclst1->setTheta(dau1_4vec.Theta());
2161 eclst1->setPhi(dau1_4vec.Phi());
2162 eclst1->setR(148.5);
2163
2164 const Particle* newDaughter0 = particles.appendNew(Particle(eclclusters[0]));
2165 daughterIndices0.push_back(newDaughter0->getArrayIndex());
2166 const Particle* par0 = particles.appendNew(momentum_0, 111, Particle::c_Unflavored, daughterIndices0);
2167
2168 const Particle* newDaughter1 = particles.appendNew(Particle(eclclusters[1]));
2169 daughterIndices1.push_back(newDaughter1->getArrayIndex());
2170 const Particle* par1 = particles.appendNew(momentum_1, 111, Particle::c_Unflavored, daughterIndices1);
2171
2172 daughterIndices2.push_back(par0->getArrayIndex());
2173 daughterIndices2.push_back(par1->getArrayIndex());
2174 const Particle* parGranny = particles.appendNew(momentum, 111, Particle::c_Unflavored, daughterIndices2);
2175 //const Particle* par = particles.appendNew(momentum, 111, Particle::c_Unflavored, daughterIndices);
2176
2177 //now we expect non-nan results
2178 EXPECT_FLOAT_EQ(std::get<double>(var_ClusterPhi->function(parGranny)), 0.32175055);
2179 EXPECT_FLOAT_EQ(std::get<double>(var_Phi->function(parGranny)), 0.32175055);
2180 EXPECT_FLOAT_EQ(std::get<double>(var_ClusterTheta->function(parGranny)), 0.06311664);
2181 EXPECT_FLOAT_EQ(std::get<double>(var_Theta->function(parGranny)), 0.06311664);
2182 EXPECT_FLOAT_EQ(std::get<double>(var_ClusterE->function(parGranny)), -0.46293831);
2183 EXPECT_FLOAT_EQ(std::get<double>(var_E->function(parGranny)), -0.46293831);
2184 }
2185
2186 TEST_F(MetaVariableTest, daughterNormDiffOf)
2187 {
2188 PxPyPzEVector momentum;
2189 const int nDaughters = 4;
2190 StoreArray<Particle> particles;
2191 std::vector<int> daughterIndices;
2192 for (int i = 0; i < nDaughters; i++) {
2193 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 1.0), (i % 2) ? -11 : 211);
2194 momentum += d.get4Vector();
2195 Particle* newDaughters = particles.appendNew(d);
2196 daughterIndices.push_back(newDaughters->getArrayIndex());
2197 }
2198 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
2199
2200 const Manager::Var* var = Manager::Instance().getVariable("daughterNormDiffOf(0, 1, PDG)");
2201 ASSERT_NE(var, nullptr);
2202 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -222 / 200.);
2203
2204 var = Manager::Instance().getVariable("daughterNormDiffOf(1, 0, PDG)");
2205 ASSERT_NE(var, nullptr);
2206 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 222 / 200.);
2207
2208 var = Manager::Instance().getVariable("daughterNormDiffOf(0, 1, abs(PDG))");
2209 ASSERT_NE(var, nullptr);
2210 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -200 / 222.);
2211
2212 var = Manager::Instance().getVariable("daughterNormDiffOf(1, 1, PDG)");
2213 ASSERT_NE(var, nullptr);
2214 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -0 / 22.);
2215
2216 var = Manager::Instance().getVariable("daughterNormDiffOf(1, 3, abs(PDG))");
2217 ASSERT_NE(var, nullptr);
2218 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0 / 22.);
2219
2220 var = Manager::Instance().getVariable("daughterNormDiffOf(0, 2, PDG)");
2221 ASSERT_NE(var, nullptr);
2222 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0 / 422.);
2223
2224 }
2225
2226 TEST_F(MetaVariableTest, daughterMotherDiffOf)
2227 {
2228 PxPyPzEVector momentum;
2229 const int nDaughters = 4;
2230 StoreArray<Particle> particles;
2231 std::vector<int> daughterIndices;
2232 for (int i = 0; i < nDaughters; i++) {
2233 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 1.0), (i % 2) ? -11 : 211);
2234 momentum += d.get4Vector();
2235 Particle* newDaughters = particles.appendNew(d);
2236 daughterIndices.push_back(newDaughters->getArrayIndex());
2237 }
2238 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
2239
2240 const Manager::Var* var = Manager::Instance().getVariable("daughterMotherDiffOf(1, PDG)");
2241 ASSERT_NE(var, nullptr);
2242 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 422);
2243
2244 var = Manager::Instance().getVariable("daughterMotherDiffOf(1, abs(PDG))");
2245 ASSERT_NE(var, nullptr);
2246 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 400);
2247
2248 var = Manager::Instance().getVariable("daughterMotherDiffOf(0, PDG)");
2249 ASSERT_NE(var, nullptr);
2250 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 200);
2251
2252 }
2253
2254 TEST_F(MetaVariableTest, daughterMotherNormDiffOf)
2255 {
2256 PxPyPzEVector momentum;
2257 const int nDaughters = 4;
2258 StoreArray<Particle> particles;
2259 std::vector<int> daughterIndices;
2260 for (int i = 0; i < nDaughters; i++) {
2261 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 1.0), (i % 2) ? -11 : 211);
2262 momentum += d.get4Vector();
2263 Particle* newDaughters = particles.appendNew(d);
2264 daughterIndices.push_back(newDaughters->getArrayIndex());
2265 }
2266 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
2267
2268 const Manager::Var* var = Manager::Instance().getVariable("daughterMotherNormDiffOf(1, PDG)");
2269 ASSERT_NE(var, nullptr);
2270 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 422 / 400.);
2271
2272 var = Manager::Instance().getVariable("daughterMotherNormDiffOf(1, abs(PDG))");
2273 ASSERT_NE(var, nullptr);
2274 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 400 / 422.);
2275
2276 var = Manager::Instance().getVariable("daughterMotherNormDiffOf(0, PDG)");
2277 ASSERT_NE(var, nullptr);
2278 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 200 / 622.);
2279
2280 }
2281
2282 TEST_F(MetaVariableTest, constant)
2283 {
2284
2285 const Manager::Var* var = Manager::Instance().getVariable("constant(1)");
2286 ASSERT_NE(var, nullptr);
2287 EXPECT_FLOAT_EQ(std::get<double>(var->function(nullptr)), 1.0);
2288
2289 var = Manager::Instance().getVariable("constant(0)");
2290 ASSERT_NE(var, nullptr);
2291 EXPECT_FLOAT_EQ(std::get<double>(var->function(nullptr)), 0.0);
2292
2293 }
2294
2295 TEST_F(MetaVariableTest, abs)
2296 {
2297 Particle p({ 0.1, -0.4, 0.8, 2.0 }, 11);
2298 Particle p2({ -0.1, -0.4, 0.8, 4.0 }, -11);
2299
2300 const Manager::Var* var = Manager::Instance().getVariable("abs(px)");
2301 ASSERT_NE(var, nullptr);
2302 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.1);
2303 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p2)), 0.1);
2304
2305 }
2306
2307 TEST_F(MetaVariableTest, sin)
2308 {
2309 Particle p({ M_PI / 2.0, -0.4, 0.8, 1.0}, 11);
2310 Particle p2({ 0.0, -0.4, 0.8, 1.0 }, -11);
2311
2312 const Manager::Var* var = Manager::Instance().getVariable("sin(px)");
2313 ASSERT_NE(var, nullptr);
2314 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.0);
2315 EXPECT_NEAR(std::get<double>(var->function(&p2)), 0.0, 1e-6);
2316
2317 }
2318
2319 TEST_F(MetaVariableTest, cos)
2320 {
2321 Particle p({ M_PI / 2.0, -0.4, 0.8, 1.0}, 11);
2322 Particle p2({ 0.0, -0.4, 0.8, 1.0 }, -11);
2323
2324 const Manager::Var* var = Manager::Instance().getVariable("cos(px)");
2325 ASSERT_NE(var, nullptr);
2326 EXPECT_NEAR(std::get<double>(var->function(&p)), 0.0, 1e-6);
2327 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p2)), 1.0);
2328
2329 }
2330
2331 TEST_F(MetaVariableTest, NBDeltaIfMissingDeathTest)
2332 {
2333 //Variable got removed, test for absence
2334 EXPECT_B2FATAL(Manager::Instance().getVariable("NBDeltaIfMissing(TOP, 11)"));
2335 EXPECT_B2FATAL(Manager::Instance().getVariable("NBDeltaIfMissing(ARICH, 11)"));
2336 }
2337
2338 TEST_F(MetaVariableTest, matchedMC)
2339 {
2341 StoreArray<MCParticle> mcParticles;
2342 StoreArray<Particle> particles;
2343 particles.registerRelationTo(mcParticles);
2345
2346 auto* mcParticle = mcParticles.appendNew();
2347 mcParticle->setPDG(Const::electron.getPDGCode());
2349 auto* p1 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
2350 p1->addRelationTo(mcParticle);
2351
2352 mcParticle = mcParticles.appendNew();
2353 mcParticle->setPDG(-Const::electron.getPDGCode());
2355 auto* p2 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
2356 p2->addRelationTo(mcParticle);
2357
2358 mcParticle = mcParticles.appendNew();
2359 mcParticle->setPDG(Const::photon.getPDGCode());
2361 auto* p3 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
2362 p3->addRelationTo(mcParticle);
2363
2364 // Test if matchedMC also works for particle which already is an MCParticle.
2365 auto* p4 = particles.appendNew(mcParticle);
2366
2367 const Manager::Var* var = Manager::Instance().getVariable("matchedMC(charge)");
2368 ASSERT_NE(var, nullptr);
2369 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), -1);
2370 EXPECT_FLOAT_EQ(std::get<double>(var->function(p2)), 1);
2371 EXPECT_FLOAT_EQ(std::get<double>(var->function(p3)), 0);
2372 EXPECT_FLOAT_EQ(std::get<double>(var->function(p4)), 0);
2373 }
2374
2375 TEST_F(MetaVariableTest, countInList)
2376 {
2377 StoreArray<Particle> particles;
2379
2380 StoreObjPtr<ParticleList> outputList("pList1");
2382 outputList.registerInDataStore(flags);
2384 outputList.create();
2385 outputList->initialize(22, "pList1");
2386
2387 particles.appendNew(Particle({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2));
2388 particles.appendNew(Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3));
2389 particles.appendNew(Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4));
2390 particles.appendNew(Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 5));
2391 particles.appendNew(Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 6));
2392
2393 outputList->addParticle(0, 22, Particle::c_Unflavored);
2394 outputList->addParticle(1, 22, Particle::c_Unflavored);
2395 outputList->addParticle(2, 22, Particle::c_Unflavored);
2396 outputList->addParticle(3, 22, Particle::c_Unflavored);
2397 outputList->addParticle(4, 22, Particle::c_Unflavored);
2398
2399 const Manager::Var* var = Manager::Instance().getVariable("countInList(pList1, E < 0.85)");
2400 ASSERT_NE(var, nullptr);
2401 EXPECT_EQ(std::get<int>(var->function(nullptr)), 2);
2402
2403 var = Manager::Instance().getVariable("countInList(pList1)");
2404 ASSERT_NE(var, nullptr);
2405 EXPECT_EQ(std::get<int>(var->function(nullptr)), 5);
2406
2407 var = Manager::Instance().getVariable("countInList(pList1, E > 5)");
2408 ASSERT_NE(var, nullptr);
2409 EXPECT_EQ(std::get<int>(var->function(nullptr)), 0);
2410
2411 var = Manager::Instance().getVariable("countInList(pList1, E < 5)");
2412 ASSERT_NE(var, nullptr);
2413 EXPECT_EQ(std::get<int>(var->function(nullptr)), 5);
2414 }
2415
2416 TEST_F(MetaVariableTest, isInList)
2417 {
2418 // we need the particles StoreArray
2419 StoreArray<Particle> particles;
2421
2422 // create a photon list for testing
2423 StoreObjPtr<ParticleList> gammalist("testGammaList");
2425 gammalist.registerInDataStore(flags);
2427 gammalist.create();
2428 gammalist->initialize(22, "testGammaList");
2429
2430 // mock up two photons
2431 Particle goingin({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0);
2432 Particle notgoingin({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1);
2433 auto* inthelist = particles.appendNew(goingin);
2434 auto* notinthelist = particles.appendNew(notgoingin);
2435
2436 // put the the zeroth one in the list the first on not in the list
2437 gammalist->addParticle(0, 22, Particle::c_Unflavored);
2438
2439 // get the variables
2440 const Manager::Var* vnonsense = Manager::Instance().getVariable("isInList(NONEXISTANTLIST)");
2441 const Manager::Var* vsensible = Manager::Instance().getVariable("isInList(testGammaList)");
2442
2443 // -
2444 EXPECT_B2FATAL(std::get<bool>(vnonsense->function(notinthelist)));
2445 EXPECT_TRUE(std::get<bool>(vsensible->function(inthelist)));
2446 EXPECT_FALSE(std::get<bool>(vsensible->function(notinthelist)));
2447 }
2448
2450 TEST_F(MetaVariableTest, cutIsInList)
2451 {
2452 StoreArray<Particle> particles;
2454
2455 // create a photon list for testing
2456 const std::string listname {"wil/d(-+)'':l*"};
2457
2458 StoreObjPtr<ParticleList> particlelist(listname);
2460 particlelist.registerInDataStore(flags);
2462 particlelist.create();
2463 particlelist->initialize(22, listname);
2464
2465 Particle goingin({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0);
2466 Particle notgoingin({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1);
2467 auto* inthelist = particles.appendNew(goingin);
2468 auto* notinthelist = particles.appendNew(notgoingin);
2469
2470 // put the the zeroth one in the list the first on not in the list
2471 particlelist->addParticle(0, 22, Particle::c_Unflavored);
2472
2473 // use passesCut metavariable to check cut parsing of isInList particle list.
2474 const Manager::Var* nonexistlist = Manager::Instance().getVariable("passesCut(isInList(NONEXISTANTLIST))");
2475 const Manager::Var* existlist = Manager::Instance().getVariable("passesCut(isInList(" + listname + "))");
2476
2477 EXPECT_B2FATAL(std::get<bool>(nonexistlist->function(inthelist)));
2478 EXPECT_FALSE(std::get<bool>(existlist->function(notinthelist)));
2479 EXPECT_TRUE(std::get<bool>(existlist->function(inthelist)));
2480 }
2481
2482 TEST_F(MetaVariableTest, sourceObjectIsInList)
2483 {
2484 // datastore things
2487
2488 // needed to mock up
2489 StoreArray<ECLCluster> clusters;
2490 StoreArray<Particle> particles;
2491 StoreObjPtr<ParticleList> gammalist("testGammaList");
2492
2493 clusters.registerInDataStore();
2494 particles.registerInDataStore();
2496 gammalist.registerInDataStore(flags);
2497
2498 // end datastore things
2500
2501 // of course we have to create the list...
2502 gammalist.create();
2503 gammalist->initialize(22, "testGammaList");
2504
2505 // mock up two clusters from the ECL let's say they both came from true Klongs
2506 // but one looked a little bit photon-like
2507 auto* cl0 = clusters.appendNew(ECLCluster());
2508 cl0->setEnergy(1.0);
2509 cl0->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
2510 cl0->addHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron);
2511 cl0->setClusterId(0);
2512 auto* cl1 = clusters.appendNew(ECLCluster());
2513 cl1->setEnergy(1.0);
2514 cl1->setHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron);
2515 cl1->setClusterId(1);
2516
2517 // create particles from the clusters
2518 Particle myphoton(cl0, Const::photon);
2519 Particle iscopiedin(cl0, Const::Klong);
2520 Particle notcopiedin(cl1, Const::Klong);
2521
2522 // add the particle created from cluster zero to the gamma list
2523 auto* myphoton_ = particles.appendNew(myphoton);
2524 gammalist->addParticle(myphoton_);
2525
2526 auto* iscopied = particles.appendNew(iscopiedin); // a clone of this guy is now in the gamma list
2527 auto* notcopied = particles.appendNew(notcopiedin);
2528
2529 // get the variables
2530 const Manager::Var* vnonsense = Manager::Instance().getVariable("sourceObjectIsInList(NONEXISTANTLIST)");
2531 const Manager::Var* vsensible = Manager::Instance().getVariable("sourceObjectIsInList(testGammaList)");
2532
2533 // -
2534 EXPECT_B2FATAL(std::get<int>(vnonsense->function(iscopied)));
2535 EXPECT_EQ(std::get<int>(vsensible->function(iscopied)), 1);
2536 EXPECT_EQ(std::get<int>(vsensible->function(notcopied)), 0);
2537
2538 // now mock up some other type particles
2539 Particle composite({0.5, 0.4, 0.5, 0.8}, 512, Particle::c_Unflavored, Particle::c_Composite, 0);
2540 Particle undefined({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1);
2541 auto* composite_ = particles.appendNew(undefined);
2542 auto* undefined_ = particles.appendNew(composite);
2543 EXPECT_EQ(std::get<int>(vsensible->function(composite_)), -1);
2544 EXPECT_EQ(std::get<int>(vsensible->function(undefined_)), -1);
2545 }
2546
2547 TEST_F(MetaVariableTest, mcParticleIsInMCList)
2548 {
2549 // datastore things
2552
2553 // needed to mock up
2554 StoreArray<MCParticle> mcparticles;
2555 StoreArray<Particle> particles;
2556 StoreObjPtr<ParticleList> list("testList");
2557 StoreObjPtr<ParticleList> anotherlist("supplimentaryList");
2558
2559 mcparticles.registerInDataStore();
2560 particles.registerInDataStore();
2561 particles.registerRelationTo(mcparticles);
2563 list.registerInDataStore(flags);
2564 anotherlist.registerInDataStore(flags);
2565
2567 // end datastore setup
2568
2569 list.create();
2570 list->initialize(22, "testList");
2571
2572 anotherlist.create();
2573 anotherlist->initialize(22, "supplimentaryList");
2574
2575 // MCParticles
2576 auto* mcphoton = mcparticles.appendNew();
2577 mcphoton->setPDG(Const::photon.getPDGCode());
2578 mcphoton->setStatus(MCParticle::c_PrimaryParticle);
2579
2580 auto* mcelectron = mcparticles.appendNew();
2581 mcelectron->setPDG(Const::electron.getPDGCode());
2582 mcelectron->setStatus(MCParticle::c_PrimaryParticle);
2583
2584 auto* mcanotherelectron = mcparticles.appendNew();
2585 mcanotherelectron->setPDG(Const::photon.getPDGCode());
2586 mcanotherelectron->setStatus(MCParticle::c_PrimaryParticle);
2587
2588 auto* mcyetanotherelectron = mcparticles.appendNew();
2589 mcyetanotherelectron->setPDG(Const::photon.getPDGCode());
2590 mcyetanotherelectron->setStatus(MCParticle::c_PrimaryParticle);
2591
2592 // particles
2593 auto* photon = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 22);
2594 photon->addRelationTo(mcphoton);
2595 list->addParticle(photon);
2596
2597 auto* electron = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 22);
2598 electron->addRelationTo(mcelectron);
2599 list->addParticle(electron);
2600
2601 auto* other = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 22);
2602 other->addRelationTo(mcanotherelectron);
2603
2604 auto* yetanotherelectron = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 22);
2605 yetanotherelectron->addRelationTo(mcyetanotherelectron);
2606 anotherlist->addParticle(yetanotherelectron);
2607 // not in the list
2608
2609 // get the variable
2610 const Manager::Var* vnonsense = Manager::Instance().getVariable("mcParticleIsInMCList(NONEXISTANTLIST)");
2611 const Manager::Var* vsensible = Manager::Instance().getVariable("mcParticleIsInMCList(testList)");
2612
2613 // -
2614 EXPECT_B2FATAL(std::get<bool>(vnonsense->function(photon)));
2615 EXPECT_TRUE(std::get<bool>(vsensible->function(photon)));
2616 EXPECT_TRUE(std::get<bool>(vsensible->function(electron)));
2617 EXPECT_FALSE(std::get<bool>(vsensible->function(other)));
2618 EXPECT_FALSE(std::get<bool>(vsensible->function(yetanotherelectron)));
2619
2620 // now mock up some other type particles
2621 Particle composite({0.5, 0.4, 0.5, 0.8}, 512, Particle::c_Unflavored, Particle::c_Composite, 0);
2622 Particle undefined({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1);
2623 auto* composite_ = particles.appendNew(undefined);
2624 auto* undefined_ = particles.appendNew(composite);
2625 EXPECT_FALSE(std::get<bool>(vsensible->function(composite_)));
2626 EXPECT_FALSE(std::get<bool>(vsensible->function(undefined_)));
2627 }
2628
2629 TEST_F(MetaVariableTest, mostB2BAndClosestParticles)
2630 {
2631 /* Mock up an event with a "photon" and an "electron" which are nearly back to
2632 * back, and second "photon" which is close-ish to the "electron".
2633 *
2634 * Other test of non-existent / empty lists and variables also included.
2635 */
2636
2637 // Connect gearbox for CMS variables
2638 Gearbox& gearbox = Gearbox::getInstance();
2639 gearbox.setBackends({std::string("file:")});
2640 gearbox.close();
2641 gearbox.open("geometry/Belle2.xml", false);
2642
2643 // we need the particles StoreArray
2644 StoreArray<Particle> particles;
2646
2647 // create a photon list for testing
2648 StoreObjPtr<ParticleList> gammalist("testGammaList");
2649 StoreObjPtr<ParticleList> emptylist("testEmptyList");
2651 gammalist.registerInDataStore(flags);
2652 emptylist.registerInDataStore(flags);
2654 gammalist.create();
2655 gammalist->initialize(22, "testGammaList");
2656 emptylist.create();
2657 emptylist->initialize(22, "testEmptyList");
2658
2659 // create some photons in an stdvector
2660 std::vector<Particle> gammavector = {
2661 Particle({ -1.0, -1.0, 0.8, 1.7}, // this should be the most b2b to our reference particle
2662 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
2663 Particle({0.2, 0.7, 0.9, 3.4}, // should be the closest
2664 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
2665 };
2666 // put the photons in the StoreArray
2667 for (const auto& g : gammavector)
2668 particles.appendNew(g);
2669
2670 // put the photons in the test list
2671 for (size_t i = 0; i < gammavector.size(); i++)
2672 gammalist->addParticle(i, 22, Particle::c_Unflavored);
2673
2674 // add the reference particle (electron) to the StoreArray
2675 const auto* electron = particles.appendNew(
2676 Particle({1.0, 1.0, 0.5, 1.6}, // somewhere in the +ve quarter of the detector
2677 11, Particle::c_Unflavored, Particle::c_Undefined, 2) // needs to be incremented if we add to gamma vector
2678 );
2679
2680 {
2681 EXPECT_B2FATAL(Manager::Instance().getVariable("angleToClosestInList"));
2682 EXPECT_B2FATAL(Manager::Instance().getVariable("angleToClosestInList(A, B)"));
2683
2684 const auto* nonexistent = Manager::Instance().getVariable("angleToClosestInList(NONEXISTANTLIST)");
2685 EXPECT_B2FATAL(std::get<double>(nonexistent->function(electron)));
2686
2687 const auto* empty = Manager::Instance().getVariable("angleToClosestInList(testEmptyList)");
2688 EXPECT_TRUE(std::isnan(std::get<double>(empty->function(electron))));
2689
2690 const auto* closest = Manager::Instance().getVariable("angleToClosestInList(testGammaList)");
2691 EXPECT_FLOAT_EQ(std::get<double>(closest->function(electron)), 0.68014491);
2692
2693 const auto* closestCMS = Manager::Instance().getVariable("useCMSFrame(angleToClosestInList(testGammaList))");
2694 EXPECT_FLOAT_EQ(std::get<double>(closestCMS->function(electron)), 0.67901474);
2695 }
2696
2697 {
2698 EXPECT_B2FATAL(Manager::Instance().getVariable("closestInList"));
2699 EXPECT_B2FATAL(Manager::Instance().getVariable("closestInList(A, B, C)"));
2700
2701 const auto* nonexistent = Manager::Instance().getVariable("closestInList(NONEXISTANTLIST, E)");
2702 EXPECT_B2FATAL(std::get<double>(nonexistent->function(electron)));
2703
2704 const auto* empty = Manager::Instance().getVariable("closestInList(testEmptyList, E)");
2705 EXPECT_TRUE(std::isnan(std::get<double>(empty->function(electron))));
2706
2707 const auto* closest = Manager::Instance().getVariable("closestInList(testGammaList, E)");
2708 EXPECT_FLOAT_EQ(std::get<double>(closest->function(electron)), 3.4);
2709
2710 const auto* closestCMS = Manager::Instance().getVariable("useCMSFrame(closestInList(testGammaList, E))");
2711 EXPECT_FLOAT_EQ(std::get<double>(closestCMS->function(electron)), 3.2732551); // the energy gets smeared because of boost
2712
2713 const auto* closestCMSLabE = Manager::Instance().getVariable("useCMSFrame(closestInList(testGammaList, useLabFrame(E)))");
2714 EXPECT_FLOAT_EQ(std::get<double>(closestCMSLabE->function(electron)), 3.4); // aaand should be back to the lab frame value
2715 }
2716
2717 {
2718 EXPECT_B2FATAL(Manager::Instance().getVariable("angleToMostB2BInList"));
2719 EXPECT_B2FATAL(Manager::Instance().getVariable("angleToMostB2BInList(A, B)"));
2720
2721 const auto* nonexistent = Manager::Instance().getVariable("angleToMostB2BInList(NONEXISTANTLIST)");
2722 EXPECT_B2FATAL(std::get<double>(nonexistent->function(electron)));
2723
2724 const auto* empty = Manager::Instance().getVariable("angleToMostB2BInList(testEmptyList)");
2725 EXPECT_TRUE(std::isnan(std::get<double>(empty->function(electron))));
2726
2727 const auto* mostB2B = Manager::Instance().getVariable("angleToMostB2BInList(testGammaList)");
2728 EXPECT_FLOAT_EQ(std::get<double>(mostB2B->function(electron)), 2.2869499);
2729
2730 const auto* mostB2BCMS = Manager::Instance().getVariable("useCMSFrame(angleToMostB2BInList(testGammaList))");
2731 EXPECT_FLOAT_EQ(std::get<double>(mostB2BCMS->function(electron)), 2.8312778);
2732 }
2733
2734 {
2735 EXPECT_B2FATAL(Manager::Instance().getVariable("mostB2BInList"));
2736 EXPECT_B2FATAL(Manager::Instance().getVariable("mostB2BInList(A, B, C)"));
2737
2738 const auto* nonexistent = Manager::Instance().getVariable("mostB2BInList(NONEXISTANTLIST, E)");
2739 EXPECT_B2FATAL(std::get<double>(nonexistent->function(electron)));
2740
2741 const auto* empty = Manager::Instance().getVariable("mostB2BInList(testEmptyList, E)");
2742 EXPECT_TRUE(std::isnan(std::get<double>(empty->function(electron))));
2743
2744 const auto* mostB2B = Manager::Instance().getVariable("mostB2BInList(testGammaList, E)");
2745 EXPECT_FLOAT_EQ(std::get<double>(mostB2B->function(electron)), 1.7);
2746
2747 const auto* mostB2BCMS = Manager::Instance().getVariable("useCMSFrame(mostB2BInList(testGammaList, E))");
2748 EXPECT_FLOAT_EQ(std::get<double>(mostB2BCMS->function(electron)), 1.5848758); // the energy gets smeared because of boost
2749
2750 const auto* mostB2BCMSLabE = Manager::Instance().getVariable("useCMSFrame(mostB2BInList(testGammaList, useLabFrame(E)))");
2751 EXPECT_FLOAT_EQ(std::get<double>(mostB2BCMSLabE->function(electron)), 1.7); // aaand should be back to the lab frame value
2752 }
2753 }
2754
2755 TEST_F(MetaVariableTest, totalEnergyOfParticlesInList)
2756 {
2757 // we need the particles StoreArray
2758 StoreArray<Particle> particles;
2760
2761 // create a photon list for testing
2762 StoreObjPtr<ParticleList> gammalist("testGammaList");
2764 gammalist.registerInDataStore(flags);
2766 gammalist.create();
2767 gammalist->initialize(22, "testGammaList");
2768
2769 // create some photons in an stdvector
2770 std::vector<Particle> gammavector = {
2771 Particle({0.5, 0.4, 0.4, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
2772 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
2773 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
2774 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
2775 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
2776 };
2777
2778 // put the photons in the StoreArray
2779 for (const auto& g : gammavector)
2780 particles.appendNew(g);
2781
2782 // put the photons in the test list
2783 for (size_t i = 0; i < gammavector.size(); i++)
2784 gammalist->addParticle(i, 22, Particle::c_Unflavored);
2785
2786 // get their total energy
2787 const Manager::Var* vnonsense = Manager::Instance().getVariable(
2788 "totalEnergyOfParticlesInList(NONEXISTANTLIST)");
2789 const Manager::Var* vsensible = Manager::Instance().getVariable(
2790 "totalEnergyOfParticlesInList(testGammaList)");
2791
2792 // -
2793 EXPECT_B2FATAL(std::get<double>(vnonsense->function(nullptr)));
2794 EXPECT_FLOAT_EQ(std::get<double>(vsensible->function(nullptr)), 4.3);
2795 }
2796 TEST_F(MetaVariableTest, totalPxOfParticlesInList)
2797 {
2798 // we need the particles StoreArray
2799 StoreArray<Particle> particles;
2801
2802 // create a photon list for testing
2803 StoreObjPtr<ParticleList> gammalist("testGammaList");
2805 gammalist.registerInDataStore(flags);
2807 gammalist.create();
2808 gammalist->initialize(22, "testGammaList");
2809
2810 // create some photons in an stdvector
2811 std::vector<Particle> gammavector = {
2812 Particle({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
2813 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
2814 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
2815 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
2816 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
2817 };
2818
2819 // put the photons in the StoreArray
2820 for (const auto& g : gammavector)
2821 particles.appendNew(g);
2822
2823 // put the photons in the test list
2824 for (size_t i = 0; i < gammavector.size(); i++)
2825 gammalist->addParticle(i, 22, Particle::c_Unflavored);
2826
2827 // get their total energy
2828 const Manager::Var* vnonsense = Manager::Instance().getVariable(
2829 "totalPxOfParticlesInList(NONEXISTANTLIST)");
2830 const Manager::Var* vsensible = Manager::Instance().getVariable(
2831 "totalPxOfParticlesInList(testGammaList)");
2832
2833 // -
2834 EXPECT_B2FATAL(std::get<double>(vnonsense->function(nullptr)));
2835 EXPECT_FLOAT_EQ(std::get<double>(vsensible->function(nullptr)), 2.2);
2836 }
2837 TEST_F(MetaVariableTest, totalPyOfParticlesInList)
2838 {
2839 // we need the particles StoreArray
2840 StoreArray<Particle> particles;
2842
2843 // create a photon list for testing
2844 StoreObjPtr<ParticleList> gammalist("testGammaList");
2846 gammalist.registerInDataStore(flags);
2848 gammalist.create();
2849 gammalist->initialize(22, "testGammaList");
2850
2851 // create some photons in an stdvector
2852 std::vector<Particle> gammavector = {
2853 Particle({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
2854 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
2855 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
2856 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
2857 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
2858 };
2859
2860 // put the photons in the StoreArray
2861 for (const auto& g : gammavector)
2862 particles.appendNew(g);
2863
2864 // put the photons in the test list
2865 for (size_t i = 0; i < gammavector.size(); i++)
2866 gammalist->addParticle(i, 22, Particle::c_Unflavored);
2867
2868 // get their total energy
2869 const Manager::Var* vnonsense = Manager::Instance().getVariable(
2870 "totalPyOfParticlesInList(NONEXISTANTLIST)");
2871 const Manager::Var* vsensible = Manager::Instance().getVariable(
2872 "totalPyOfParticlesInList(testGammaList)");
2873
2874 // -
2875 EXPECT_B2FATAL(std::get<double>(vnonsense->function(nullptr)));
2876 EXPECT_FLOAT_EQ(std::get<double>(vsensible->function(nullptr)), 1.5);
2877 }
2878 TEST_F(MetaVariableTest, totalPzOfParticlesInList)
2879 {
2880 // we need the particles StoreArray
2881 StoreArray<Particle> particles;
2883
2884 // create a photon list for testing
2885 StoreObjPtr<ParticleList> gammalist("testGammaList");
2887 gammalist.registerInDataStore(flags);
2889 gammalist.create();
2890 gammalist->initialize(22, "testGammaList");
2891
2892 // create some photons in an stdvector
2893 std::vector<Particle> gammavector = {
2894 Particle({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
2895 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
2896 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
2897 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
2898 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
2899 };
2900
2901 // put the photons in the StoreArray
2902 for (const auto& g : gammavector)
2903 particles.appendNew(g);
2904
2905 // put the photons in the test list
2906 for (size_t i = 0; i < gammavector.size(); i++)
2907 gammalist->addParticle(i, 22, Particle::c_Unflavored);
2908
2909 // get their total energy
2910 const Manager::Var* vnonsense = Manager::Instance().getVariable(
2911 "totalPzOfParticlesInList(NONEXISTANTLIST)");
2912 const Manager::Var* vsensible = Manager::Instance().getVariable(
2913 "totalPzOfParticlesInList(testGammaList)");
2914
2915 // -
2916 EXPECT_B2FATAL(std::get<double>(vnonsense->function(nullptr)));
2917 EXPECT_FLOAT_EQ(std::get<double>(vsensible->function(nullptr)), 3.1);
2918 }
2919 TEST_F(MetaVariableTest, maxPtInList)
2920 {
2921 // we need the particles StoreArray
2922 StoreArray<Particle> particles;
2924
2925 // create a photon list for testing
2926 StoreObjPtr<ParticleList> gammalist("testGammaList");
2928 gammalist.registerInDataStore(flags);
2930 gammalist.create();
2931 gammalist->initialize(22, "testGammaList");
2932
2933 // create some photons in an stdvector
2934 std::vector<Particle> gammavector = {
2935 Particle({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
2936 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
2937 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
2938 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
2939 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
2940 };
2941
2942 // put the photons in the StoreArray
2943 for (const auto& g : gammavector)
2944 particles.appendNew(g);
2945
2946 // put the photons in the test list
2947 for (size_t i = 0; i < gammavector.size(); i++)
2948 gammalist->addParticle(i, 22, Particle::c_Unflavored);
2949
2950 // get their total energy
2951 const Manager::Var* vnonsense = Manager::Instance().getVariable(
2952 "maxPtInList(NONEXISTANTLIST)");
2953 const Manager::Var* vsensible = Manager::Instance().getVariable(
2954 "maxPtInList(testGammaList)");
2955
2956 // -
2957 EXPECT_B2FATAL(std::get<double>(vnonsense->function(nullptr)));
2958 EXPECT_FLOAT_EQ(std::get<double>(vsensible->function(nullptr)), sqrt(0.5 * 0.5 + 0.4 * 0.4));
2959 }
2960
2961
2962 TEST_F(MetaVariableTest, numberOfNonOverlappingParticles)
2963 {
2964 StoreArray<Particle> particles;
2966
2967 StoreObjPtr<ParticleList> outputList("pList1");
2969 outputList.registerInDataStore(flags);
2971 outputList.create();
2972 outputList->initialize(22, "pList1");
2973
2974 auto* p1 = particles.appendNew(Particle({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2));
2975 auto* p2 = particles.appendNew(Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3));
2976 auto* p3 = particles.appendNew(Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4));
2977
2978 outputList->addParticle(0, 22, Particle::c_Unflavored);
2979 outputList->addParticle(1, 22, Particle::c_Unflavored);
2980
2981 const Manager::Var* var = Manager::Instance().getVariable("numberOfNonOverlappingParticles(pList1)");
2982 ASSERT_NE(var, nullptr);
2983 EXPECT_EQ(std::get<int>(var->function(p1)), 1);
2984 EXPECT_EQ(std::get<int>(var->function(p2)), 1);
2985 EXPECT_EQ(std::get<int>(var->function(p3)), 2);
2986
2987 }
2988
2989 TEST_F(MetaVariableTest, veto)
2990 {
2991 StoreArray<Particle> particles;
2993
2994 const Particle* p = particles.appendNew(Particle({0.8, 0.8, 1.131370849898476039041351, 1.6}, 22,
2995 Particle::c_Unflavored, Particle::c_Undefined, 1));
2996
2997 StoreObjPtr<ParticleList> outputList("pList1");
2999 outputList.registerInDataStore(flags);
3001 outputList.create();
3002 outputList->initialize(22, "pList1");
3003
3004 particles.appendNew(Particle({0.5, 0.4953406774856531014212777, 0.5609256753154148484773173, 0.9}, 22,
3005 Particle::c_Unflavored, Particle::c_Undefined, 2)); //m=0.135
3006 particles.appendNew(Particle({0.5, 0.2, 0.72111, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3)); //m=0.3582
3007 particles.appendNew(Particle({0.4, 0.2, 0.78102, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)); //m=0.3908
3008 particles.appendNew(Particle({0.5, 0.4, 0.89443, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 5)); //m=0.2369
3009 particles.appendNew(Particle({0.3, 0.3, 0.42426, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 6)); //m=0.0036
3010
3011 outputList->addParticle(1, 22, Particle::c_Unflavored);
3012 outputList->addParticle(2, 22, Particle::c_Unflavored);
3013 outputList->addParticle(3, 22, Particle::c_Unflavored);
3014 outputList->addParticle(4, 22, Particle::c_Unflavored);
3015 outputList->addParticle(5, 22, Particle::c_Unflavored);
3016
3017 StoreObjPtr<ParticleList> outputList2("pList2");
3019 outputList2.registerInDataStore(flags);
3021 outputList2.create();
3022 outputList2->initialize(22, "pList2");
3023
3024 particles.appendNew(Particle({0.5, -0.4, 0.63246, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 7)); //m=1.1353
3025 particles.appendNew(Particle({0.5, 0.2, 0.72111, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 8)); //m=0.3582
3026 particles.appendNew(Particle({0.4, 0.2, 0.78102, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 9)); //m=0.3908
3027 particles.appendNew(Particle({0.5, 0.4, 0.89443, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 10)); //m=0.2369
3028 particles.appendNew(Particle({0.3, 0.3, 0.42426, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 11)); //m=0.0036
3029
3030 outputList2->addParticle(6, 22, Particle::c_Unflavored);
3031 outputList2->addParticle(7, 22, Particle::c_Unflavored);
3032 outputList2->addParticle(8, 22, Particle::c_Unflavored);
3033 outputList2->addParticle(9, 22, Particle::c_Unflavored);
3034 outputList2->addParticle(10, 22, Particle::c_Unflavored);
3035
3036 const Manager::Var* var = Manager::Instance().getVariable("veto(pList1, 0.130 < M < 0.140, 22)");
3037 ASSERT_NE(var, nullptr);
3038 EXPECT_TRUE(std::get<bool>(var->function(p)));
3039
3040 var = Manager::Instance().getVariable("veto(pList2, 0.130 < M < 0.140, 22)");
3041 ASSERT_NE(var, nullptr);
3042 EXPECT_FALSE(std::get<bool>(var->function(p)));
3043
3044 }
3045
3046 TEST_F(MetaVariableTest, averageValueInList)
3047 {
3048 // we need the particles StoreArray
3049 StoreArray<Particle> particles;
3051
3052 // create a photon list for testing
3053 StoreObjPtr<ParticleList> gammalist("testGammaList");
3055 gammalist.registerInDataStore(flags);
3057 gammalist.create();
3058 gammalist->initialize(22, "testGammaList");
3059
3060 // create some photons in an stdvector
3061 std::vector<Particle> gammavector = {
3062 Particle({0.5, 0.4, 0.4, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
3063 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
3064 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
3065 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
3066 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
3067 };
3068
3069 // put the photons in the StoreArray
3070 for (const auto& g : gammavector)
3071 particles.appendNew(g);
3072
3073 // put the photons in the test list
3074 for (size_t i = 0; i < gammavector.size(); i++)
3075 gammalist->addParticle(i, 22, Particle::c_Unflavored);
3076
3077 // get the average px, py, pz, E of the gammas in the list
3078 const Manager::Var* vmeanpx = Manager::Instance().getVariable(
3079 "averageValueInList(testGammaList, px)");
3080 const Manager::Var* vmeanpy = Manager::Instance().getVariable(
3081 "averageValueInList(testGammaList, py)");
3082 const Manager::Var* vmeanpz = Manager::Instance().getVariable(
3083 "averageValueInList(testGammaList, pz)");
3084 const Manager::Var* vmeanE = Manager::Instance().getVariable(
3085 "averageValueInList(testGammaList, E)");
3086
3087 EXPECT_FLOAT_EQ(std::get<double>(vmeanpx->function(nullptr)), 0.44);
3088 EXPECT_FLOAT_EQ(std::get<double>(vmeanpy->function(nullptr)), 0.3);
3089 EXPECT_FLOAT_EQ(std::get<double>(vmeanpz->function(nullptr)), 0.6);
3090 EXPECT_FLOAT_EQ(std::get<double>(vmeanE->function(nullptr)), 0.86);
3091
3092 // wrong number of arguments (no variable provided)
3093 EXPECT_B2FATAL(Manager::Instance().getVariable("averageValueInList(testGammaList)"));
3094
3095 // non-existing variable
3096 EXPECT_B2FATAL(Manager::Instance().getVariable("averageValueInList(testGammaList, NONEXISTANTVARIABLE)"));
3097
3098 // non-existing list
3099 const Manager::Var* vnolist = Manager::Instance().getVariable(
3100 "averageValueInList(NONEXISTANTLIST, px)");
3101
3102 EXPECT_B2FATAL(std::get<double>(vnolist->function(nullptr)));
3103 }
3104
3105 TEST_F(MetaVariableTest, medianValueInList)
3106 {
3107 // we need the particles StoreArray
3108 StoreArray<Particle> particles;
3110
3111 // create two photon lists for testing (one with odd and one with even number of particles)
3112 StoreObjPtr<ParticleList> oddgammalist("oddGammaList");
3114 oddgammalist.registerInDataStore(flags);
3116 oddgammalist.create();
3117 oddgammalist->initialize(22, "oddGammaList");
3118 StoreObjPtr<ParticleList> evengammalist("evenGammaList");
3120 evengammalist.registerInDataStore(flags);
3122 evengammalist.create();
3123 evengammalist->initialize(22, "evenGammaList");
3124
3125 // create some photons in an stdvector
3126 std::vector<Particle> gammavector = {
3127 Particle({0.5, 0.4, 0.4, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
3128 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
3129 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
3130 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
3131 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
3132 };
3133
3134 // put the photons in the StoreArray
3135 for (const auto& g : gammavector)
3136 particles.appendNew(g);
3137
3138 // put the photons in the test lists
3139 oddgammalist->addParticle(0, 22, Particle::c_Unflavored);
3140 for (size_t i = 1; i < gammavector.size(); i++) {
3141 oddgammalist->addParticle(i, 22, Particle::c_Unflavored);
3142 evengammalist->addParticle(i, 22, Particle::c_Unflavored);
3143 }
3144
3145 // get the median px, py, pz, E of the gammas in the list with odd number of particles
3146 const Manager::Var* voddmedianpx = Manager::Instance().getVariable(
3147 "medianValueInList(oddGammaList, px)");
3148 const Manager::Var* voddmedianpy = Manager::Instance().getVariable(
3149 "medianValueInList(oddGammaList, py)");
3150 const Manager::Var* voddmedianpz = Manager::Instance().getVariable(
3151 "medianValueInList(oddGammaList, pz)");
3152 const Manager::Var* voddmedianE = Manager::Instance().getVariable(
3153 "medianValueInList(oddGammaList, E)");
3154
3155 EXPECT_FLOAT_EQ(std::get<double>(voddmedianpx->function(nullptr)), 0.5);
3156 EXPECT_FLOAT_EQ(std::get<double>(voddmedianpy->function(nullptr)), 0.3);
3157 EXPECT_FLOAT_EQ(std::get<double>(voddmedianpz->function(nullptr)), 0.7);
3158 EXPECT_FLOAT_EQ(std::get<double>(voddmedianE->function(nullptr)), 0.9);
3159
3160 // get the median px, py, pz, E of the gammas in the list with odd number of particles
3161 const Manager::Var* vevenmedianpx = Manager::Instance().getVariable(
3162 "medianValueInList(evenGammaList, px)");
3163 const Manager::Var* vevenmedianpy = Manager::Instance().getVariable(
3164 "medianValueInList(evenGammaList, py)");
3165 const Manager::Var* vevenmedianpz = Manager::Instance().getVariable(
3166 "medianValueInList(evenGammaList, pz)");
3167 const Manager::Var* vevenmedianE = Manager::Instance().getVariable(
3168 "medianValueInList(evenGammaList, E)");
3169
3170 EXPECT_FLOAT_EQ(std::get<double>(vevenmedianpx->function(nullptr)), 0.45);
3171 EXPECT_FLOAT_EQ(std::get<double>(vevenmedianpy->function(nullptr)), 0.25);
3172 EXPECT_FLOAT_EQ(std::get<double>(vevenmedianpz->function(nullptr)), 0.7);
3173 EXPECT_FLOAT_EQ(std::get<double>(vevenmedianE->function(nullptr)), 0.9);
3174
3175 // wrong number of arguments (no variable provided)
3176 EXPECT_B2FATAL(Manager::Instance().getVariable("medianValueInList(oddGammaList)"));
3177
3178 // non-existing variable
3179 EXPECT_B2FATAL(Manager::Instance().getVariable("medianValueInList(oddGammaList, NONEXISTANTVARIABLE)"));
3180
3181 // non-existing list
3182 const Manager::Var* vnolist = Manager::Instance().getVariable(
3183 "medianValueInList(NONEXISTANTLIST, px)");
3184
3185 EXPECT_B2FATAL(std::get<double>(vnolist->function(nullptr)));
3186 }
3187
3188 TEST_F(MetaVariableTest, productValueInList)
3189 {
3190 // we need the particles StoreArray
3191 StoreArray<Particle> particles;
3193
3194 // create a photon list for testing
3195 StoreObjPtr<ParticleList> gammalist("testGammaList");
3197 gammalist.registerInDataStore(flags);
3199 gammalist.create();
3200 gammalist->initialize(22, "testGammaList");
3201
3202 // create some photons in an stdvector
3203 std::vector<Particle> gammavector = {
3204 Particle({0.5, 0.4, 0.4, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
3205 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
3206 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
3207 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
3208 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
3209 };
3210
3211 // put the photons in the StoreArray
3212 for (const auto& g : gammavector)
3213 particles.appendNew(g);
3214
3215 // put the photons in the test list
3216 for (size_t i = 0; i < gammavector.size(); i++)
3217 gammalist->addParticle(i, 22, Particle::c_Unflavored);
3218
3219 // get the product of the px, py, pz, E of the gammas in the list
3220 const Manager::Var* vproductpx = Manager::Instance().getVariable(
3221 "productValueInList(testGammaList, px)");
3222 const Manager::Var* vproductpy = Manager::Instance().getVariable(
3223 "productValueInList(testGammaList, py)");
3224 const Manager::Var* vproductpz = Manager::Instance().getVariable(
3225 "productValueInList(testGammaList, pz)");
3226 const Manager::Var* vproductE = Manager::Instance().getVariable(
3227 "productValueInList(testGammaList, E)");
3228
3229 EXPECT_FLOAT_EQ(std::get<double>(vproductpx->function(nullptr)), 0.015);
3230 EXPECT_FLOAT_EQ(std::get<double>(vproductpy->function(nullptr)), 0.00192);
3231 EXPECT_FLOAT_EQ(std::get<double>(vproductpz->function(nullptr)), 0.06272);
3232 EXPECT_FLOAT_EQ(std::get<double>(vproductE->function(nullptr)), 0.42768);
3233
3234 // wrong number of arguments (no variable provided)
3235 EXPECT_B2FATAL(Manager::Instance().getVariable("productValueInList(testGammaList)"));
3236
3237 // non-existing variable
3238 EXPECT_B2FATAL(Manager::Instance().getVariable("productValueInList(testGammaList, NONEXISTANTVARIABLE)"));
3239
3240 // non-existing list
3241 const Manager::Var* vnolist = Manager::Instance().getVariable(
3242 "productValueInList(NONEXISTANTLIST, px)");
3243
3244 EXPECT_B2FATAL(std::get<double>(vnolist->function(nullptr)));
3245 }
3246
3247 TEST_F(MetaVariableTest, sumValueInList)
3248 {
3249 // we need the particles StoreArray
3250 StoreArray<Particle> particles;
3252
3253 // create a photon list for testing
3254 StoreObjPtr<ParticleList> gammalist("testGammaList");
3256 gammalist.registerInDataStore(flags);
3258 gammalist.create();
3259 gammalist->initialize(22, "testGammaList");
3260
3261 // create some photons in an stdvector
3262 std::vector<Particle> gammavector = {
3263 Particle({0.5, 0.4, 0.4, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
3264 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
3265 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
3266 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
3267 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
3268 };
3269
3270 // put the photons in the StoreArray
3271 for (const auto& g : gammavector)
3272 particles.appendNew(g);
3273
3274 // put the photons in the test list
3275 for (size_t i = 0; i < gammavector.size(); i++)
3276 gammalist->addParticle(i, 22, Particle::c_Unflavored);
3277
3278 // get the summed px, py, pz, E of the gammas in the list
3279 const Manager::Var* vsumpx = Manager::Instance().getVariable(
3280 "sumValueInList(testGammaList, px)");
3281 const Manager::Var* vsumpy = Manager::Instance().getVariable(
3282 "sumValueInList(testGammaList, py)");
3283 const Manager::Var* vsumpz = Manager::Instance().getVariable(
3284 "sumValueInList(testGammaList, pz)");
3286 "sumValueInList(testGammaList, E)");
3287
3288 EXPECT_FLOAT_EQ(std::get<double>(vsumpx->function(nullptr)), 2.2);
3289 EXPECT_FLOAT_EQ(std::get<double>(vsumpy->function(nullptr)), 1.5);
3290 EXPECT_FLOAT_EQ(std::get<double>(vsumpz->function(nullptr)), 3.0);
3291 EXPECT_FLOAT_EQ(std::get<double>(vsumE->function(nullptr)), 4.3);
3292
3293 // wrong number of arguments (no variable provided)
3294 EXPECT_B2FATAL(Manager::Instance().getVariable("sumValueInList(testGammaList)"));
3295
3296 // non-existing variable
3297 EXPECT_B2FATAL(Manager::Instance().getVariable("sumValueInList(testGammaList, NONEXISTANTVARIABLE)"));
3298
3299 // non-existing list
3300 const Manager::Var* vnolist = Manager::Instance().getVariable(
3301 "sumValueInList(NONEXISTANTLIST, px)");
3302
3303 EXPECT_B2FATAL(std::get<double>(vnolist->function(nullptr)));
3304 }
3305
3306 TEST_F(MetaVariableTest, pValueCombination)
3307 {
3308 PxPyPzEVector momentum;
3309 StoreArray<Particle> particles;
3310 std::vector<int> daughterIndices;
3311 Particle KS(PxPyPzEVector(1.164, 1.55200, 0, 2), 310, Particle::c_Unflavored, Particle::c_Composite, 0);
3312 KS.setPValue(0.1);
3313 momentum += KS.get4Vector();
3314 Particle* newDaughters = particles.appendNew(KS);
3315 daughterIndices.push_back(newDaughters->getArrayIndex());
3316 Particle Jpsi(PxPyPzEVector(-1, 1, 1, 3.548), 443, Particle::c_Unflavored, Particle::c_Composite, 1);
3317 Jpsi.setPValue(0.9);
3318 momentum += Jpsi.get4Vector();
3319 newDaughters = particles.appendNew(Jpsi);
3320 daughterIndices.push_back(newDaughters->getArrayIndex());
3321 Particle* B = particles.appendNew(momentum, 521, Particle::c_Flavored, daughterIndices);
3322 B->setPValue(0.5);
3323
3324 const Manager::Var* singlePvalue = Manager::Instance().getVariable("pValueCombination(chiProb)");
3325 ASSERT_NE(singlePvalue, nullptr);
3326 EXPECT_FLOAT_EQ(std::get<double>(singlePvalue->function(B)), 0.5);
3327
3328 const Manager::Var* twoPvalues = Manager::Instance().getVariable("pValueCombination(chiProb, daughter(0, chiProb))");
3329 ASSERT_NE(twoPvalues, nullptr);
3330 EXPECT_FLOAT_EQ(std::get<double>(twoPvalues->function(B)), 0.05 * (1 - log(0.05)));
3331
3332 const Manager::Var* threePvalues =
3333 Manager::Instance().getVariable("pValueCombination(chiProb, daughter(0, chiProb), daughter(1, chiProb))");
3334 ASSERT_NE(threePvalues, nullptr);
3335 EXPECT_FLOAT_EQ(std::get<double>(threePvalues->function(B)), 0.045 * (1 - log(0.045) + 0.5 * log(0.045) * log(0.045)));
3336
3337 // wrong number of arguments
3338 EXPECT_B2FATAL(Manager::Instance().getVariable("pValueCombination()"));
3339
3340 // non-existing variable
3341 EXPECT_B2FATAL(Manager::Instance().getVariable("pValueCombination(chiProb, NONEXISTANTVARIABLE)"));
3342 }
3343
3344
3345 TEST_F(MetaVariableTest, daughterCombinationOneGeneration)
3346 {
3347 const int nDaughters = 5;
3348 PxPyPzEVector momentum(0, 0, 0, 0);
3349 StoreArray<Particle> particles;
3350 std::vector<int> daughterIndices;
3351 std::vector<PxPyPzEVector> daughterMomenta;
3352
3353 for (int i = 0; i < nDaughters; i++) {
3354 PxPyPzEVector mom(1, i * 0.5, 1, i * 1.0 + 2.0);
3355 Particle d(mom, (i % 2) ? 111 : 113);
3356 Particle* newDaughters = particles.appendNew(d);
3357 daughterIndices.push_back(newDaughters->getArrayIndex());
3358 daughterMomenta.push_back(mom);
3359 momentum = momentum + mom;
3360 }
3361 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Flavored, daughterIndices);
3362
3363 // Test the invariant mass of several combinations
3364 const Manager::Var* var = Manager::Instance().getVariable("daughterCombination(M, 0,1,2)");
3365 double M_test = (daughterMomenta[0] + daughterMomenta[1] + daughterMomenta[2]).mag();
3366 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), M_test);
3367
3368 var = Manager::Instance().getVariable("daughterCombination(M, 0,4)");
3369 M_test = (daughterMomenta[0] + daughterMomenta[4]).mag();
3370 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), M_test);
3371
3372
3373 // Try with a non-lorentz invariant quantity
3374 var = Manager::Instance().getVariable("daughterCombination(p, 1, 0, 4)");
3375 double p_test = (daughterMomenta[0] + daughterMomenta[1] + daughterMomenta[4]).P();
3376 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), p_test);
3377
3378
3379 // errors and bad stuff
3380 EXPECT_B2FATAL(Manager::Instance().getVariable("daughterCombination(aVeryNonExistingVariableSillyName, 1, 0, 4)"));
3381
3382 var = Manager::Instance().getVariable("daughterCombination(M, 1, 0, 100)");
3383 EXPECT_B2WARNING(std::get<double>(var->function(p)));
3384 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3385
3386
3387 var = Manager::Instance().getVariable("daughterCombination(M, 1, -1)");
3388 EXPECT_B2WARNING(std::get<double>(var->function(p)));
3389 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3390
3391
3392 var = Manager::Instance().getVariable("daughterCombination(M, 1, 0:1:0:0:1)");
3393 EXPECT_B2WARNING(std::get<double>(var->function(p)));
3394 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3395
3396 }
3397
3398
3399 TEST_F(MetaVariableTest, daughterCombinationTwoGenerations)
3400 {
3401 StoreArray<Particle> particles;
3402
3403 // make a 1 -> 3 particle
3404
3405 PxPyPzEVector momentum_1(0, 0, 0, 0);
3406 std::vector<PxPyPzEVector> daughterMomenta_1;
3407 std::vector<int> daughterIndices_1;
3408
3409 for (int i = 0; i < 3; i++) {
3410 PxPyPzEVector mom(i * 0.2, 1, 1, i * 1.0 + 2.0);
3411 Particle d(mom, (i % 2) ? 111 : 113);
3412 Particle* newDaughters = particles.appendNew(d);
3413 daughterIndices_1.push_back(newDaughters->getArrayIndex());
3414 daughterMomenta_1.push_back(mom);
3415 momentum_1 = momentum_1 + mom;
3416 }
3417
3418 const Particle* compositeDau_1 = particles.appendNew(momentum_1, 411, Particle::c_Flavored, daughterIndices_1);
3419
3420
3421 // make a 1 -> 2 particle
3422
3423 PxPyPzEVector momentum_2(0, 0, 0, 0);
3424 std::vector<PxPyPzEVector> daughterMomenta_2;
3425 std::vector<int> daughterIndices_2;
3426
3427 for (int i = 0; i < 2; i++) {
3428 PxPyPzEVector mom(1, 1, i * 0.3, i * 1.0 + 2.0);
3429 Particle d(mom, (i % 2) ? 111 : 113);
3430 Particle* newDaughters = particles.appendNew(d);
3431 daughterIndices_2.push_back(newDaughters->getArrayIndex());
3432 daughterMomenta_2.push_back(mom);
3433 momentum_2 = momentum_2 + mom;
3434 }
3435
3436 const Particle* compositeDau_2 = particles.appendNew(momentum_2, 411, Particle::c_Flavored, daughterIndices_2);
3437
3438
3439 // make the composite particle
3440 std::vector<int> daughterIndices = {compositeDau_1->getArrayIndex(), compositeDau_2->getArrayIndex()};
3441 const Particle* p = particles.appendNew(momentum_2 + momentum_1, 111, Particle::c_Unflavored, daughterIndices);
3442
3443
3444 // Test the invariant mass of several combinations
3445 const Manager::Var* var = Manager::Instance().getVariable("daughterCombination(M, 0,1)");
3446
3447 double M_test = (momentum_1 + momentum_2).mag();
3448 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), M_test);
3449
3450 // this should be the mass of the first daughter
3451 var = Manager::Instance().getVariable("daughterCombination(M, 0:0, 0:1, 0:2)");
3452 M_test = (momentum_1).mag();
3453 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), M_test);
3454
3455 // this should be a generic combinations
3456 var = Manager::Instance().getVariable("daughterCombination(M, 0:0, 0:1, 1:0)");
3457 M_test = (daughterMomenta_1[0] + daughterMomenta_1[1] + daughterMomenta_2[0]).mag();
3458 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), M_test);
3459
3460 }
3461
3462
3463 TEST_F(MetaVariableTest, useAlternativeDaughterHypothesis)
3464 {
3465 const int nDaughters = 5;
3466 StoreArray<Particle> particles;
3467
3468 // Build a first Particle
3469 PxPyPzEVector momentum(0, 0, 0, 0);
3470 std::vector<int> daughterIndices;
3471 for (int i = 0; i < nDaughters; i++) {
3472 double px = i * 0.1;
3473 double py = i * 0.3;
3474 double pz = -i * 0.1 - 0.2;
3475
3476 PxPyPzEVector mom(px, py, pz, 1);
3477 // all pions
3478 int pdgCode = Const::pion.getPDGCode();
3479 Particle d(mom, pdgCode);
3480 d.updateMass(pdgCode);
3481 mom = d.get4Vector();
3482
3483 Particle* daughters = particles.appendNew(d);
3484 daughterIndices.push_back(daughters->getArrayIndex());
3485 momentum = momentum + mom;
3486 }
3487 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Flavored, daughterIndices);
3488
3489
3490 // Build a second Particle with same momenta, but different mass hyp.
3491 PxPyPzEVector momentumAlt(0, 0, 0, 0);
3492 std::vector<int> daughterIndicesAlt;
3493 for (int i = 0; i < nDaughters; i++) {
3494 double px = i * 0.1;
3495 double py = i * 0.3;
3496 double pz = -i * 0.1 - 0.2;
3497
3498 PxPyPzEVector mom(px, py, pz, 1);
3499 // all pions but the first two
3500 int pdgCode = Const::pion.getPDGCode();
3501 if (i == 0)
3502 pdgCode = Const::proton.getPDGCode(); // a proton
3503 if (i == 1)
3504 pdgCode = Const::kaon.getPDGCode(); // a K
3505 Particle d(mom, pdgCode);
3506 d.updateMass(pdgCode);
3507 mom = d.get4Vector();
3508
3509 Particle* daughters = particles.appendNew(d);
3510 daughterIndicesAlt.push_back(daughters->getArrayIndex());
3511 momentumAlt = momentumAlt + mom;
3512 }
3513 const Particle* pAlt = particles.appendNew(momentumAlt, 411, Particle::c_Flavored, daughterIndicesAlt);
3514
3515
3516 // Test the invariant mass under the alternative hypothesis
3517 std::cout << "mass test" << std::endl;
3518 const Manager::Var* var = Manager::Instance().getVariable("useAlternativeDaughterHypothesis(M, 0:p+,1:K+)");
3519 const Manager::Var* varAlt = Manager::Instance().getVariable("M");
3520 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), std::get<double>(varAlt->function(pAlt)));
3521
3522 // check it's really charge-insensitive...
3523 std::cout << "charge test" << std::endl;
3524 var = Manager::Instance().getVariable("useAlternativeDaughterHypothesis(M, 0:p+,1:K-)");
3525 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), std::get<double>(varAlt->function(pAlt)));
3526
3527 // check the variable is not changing the 3-momentum
3528 std::cout << "momentum test" << std::endl;
3529 var = Manager::Instance().getVariable("useAlternativeDaughterHypothesis(p, 0:p+,1:K-)");
3530 varAlt = Manager::Instance().getVariable("p");
3531 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), std::get<double>(varAlt->function(pAlt)));
3532 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), std::get<double>(varAlt->function(p)));
3533 EXPECT_FLOAT_EQ(std::get<double>(var->function(pAlt)), std::get<double>(varAlt->function(pAlt)));
3534 }
3535
3536
3537
3538
3539 TEST_F(MetaVariableTest, daughterAngle)
3540 {
3541 StoreArray<Particle> particles;
3542
3543 // make a 1 -> 3 particle
3544
3545 PxPyPzEVector momentum_1(0, 0, 0, 0);
3546 std::vector<PxPyPzEVector> daughterMomenta_1;
3547 std::vector<int> daughterIndices_1;
3548
3549 for (int i = 0; i < 3; i++) {
3550 PxPyPzEVector mom(i * 0.2, 1, 1, i * 1.0 + 2.0);
3551 Particle d(mom, (i % 2) ? -11 : 211);
3552 Particle* newDaughters = particles.appendNew(d);
3553 daughterIndices_1.push_back(newDaughters->getArrayIndex());
3554 daughterMomenta_1.push_back(mom);
3555 momentum_1 = momentum_1 + mom;
3556 }
3557
3558 const Particle* compositeDau_1 = particles.appendNew(momentum_1, 411, Particle::c_Flavored, daughterIndices_1);
3559
3560
3561 // make a 1 -> 2 particle
3562
3563 PxPyPzEVector momentum_2(0, 0, 0, 0);
3564 std::vector<PxPyPzEVector> daughterMomenta_2;
3565 std::vector<int> daughterIndices_2;
3566
3567 for (int i = 0; i < 2; i++) {
3568 PxPyPzEVector mom(1, 1, i * 0.3, i * 1.0 + 2.0);
3569 Particle d(mom, (i % 2) ? -11 : 211);
3570 Particle* newDaughters = particles.appendNew(d);
3571 daughterIndices_2.push_back(newDaughters->getArrayIndex());
3572 daughterMomenta_2.push_back(mom);
3573 momentum_2 = momentum_2 + mom;
3574 }
3575
3576 const Particle* compositeDau_2 = particles.appendNew(momentum_2, 411, Particle::c_Flavored, daughterIndices_2);
3577
3578
3579 // make the composite particle
3580 std::vector<int> daughterIndices = {compositeDau_1->getArrayIndex(), compositeDau_2->getArrayIndex()};
3581 const Particle* p = particles.appendNew(momentum_2 + momentum_1, 111, Particle::c_Unflavored, daughterIndices);
3582
3583
3584 // Test the invariant mass of several combinations
3585 const Manager::Var* var = Manager::Instance().getVariable("daughterAngle(0, 1)");
3586 double v_test = acos(momentum_1.Vect().Unit().Dot(momentum_2.Vect().Unit()));
3587
3588 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), v_test);
3589
3590 // this should be a generic combinations
3591 var = Manager::Instance().getVariable("daughterAngle(0:0, 1:0)");
3592 v_test = acos(daughterMomenta_1[0].Vect().Unit().Dot(daughterMomenta_2[0].Vect().Unit()));
3593 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), v_test);
3594
3595 var = Manager::Instance().getVariable("daughterAngle( 1, -1)");
3596 EXPECT_B2WARNING(std::get<double>(var->function(p)));
3597 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3598
3599 var = Manager::Instance().getVariable("daughterAngle(1, 0:1:0:0:1)");
3600 EXPECT_B2WARNING(std::get<double>(var->function(p)));
3601 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3602
3603 }
3604
3605 TEST_F(MetaVariableTest, mcDaughterVariables)
3606 {
3607
3609 StoreArray<Particle> particles;
3610 StoreArray<MCParticle> mcParticles;
3611 particles.registerRelationTo(mcParticles);
3613 // make a 1 -> 3 particle
3614
3615 PxPyPzEVector momentum_1(0, 0, 0, 0);
3616 std::vector<PxPyPzEVector> daughterMomenta_1;
3617 std::vector<int> daughterIndices_1;
3618
3619 for (int i = 0; i < 3; i++) {
3620 PxPyPzEVector mom(i * 0.2, 1, 1, i * 1.0 + 2.0);
3621 Particle d(mom, (i % 2) ? -11 : 211);
3622 Particle* newDaughters = particles.appendNew(d);
3623 daughterIndices_1.push_back(newDaughters->getArrayIndex());
3624 daughterMomenta_1.push_back(mom);
3625 momentum_1 = momentum_1 + mom;
3626
3627 auto* mcParticle = mcParticles.appendNew();
3628 mcParticle->setPDG((i % 2) ? -Const::electron.getPDGCode() : Const::pion.getPDGCode());
3630 mcParticle->set4Vector(mom);
3631 newDaughters->addRelationTo(mcParticle);
3632 }
3633
3634 const Particle* compositeDau_1 = particles.appendNew(momentum_1, 411, Particle::c_Flavored, daughterIndices_1);
3635 auto* mcCompositeDau_1 = mcParticles.appendNew();
3636 mcCompositeDau_1->setPDG(411);
3637 mcCompositeDau_1->setStatus(MCParticle::c_PrimaryParticle);
3638 mcCompositeDau_1->set4Vector(momentum_1);
3639 compositeDau_1->addRelationTo(mcCompositeDau_1);
3640
3641 // make a 1 -> 2 particle
3642
3643 PxPyPzEVector momentum_2(0, 0, 0, 0);
3644 std::vector<PxPyPzEVector> daughterMomenta_2;
3645 std::vector<int> daughterIndices_2;
3646
3647 for (int i = 0; i < 2; i++) {
3648 PxPyPzEVector mom(1, 1, i * 0.3, i * 1.0 + 2.0);
3649 Particle d(mom, (i % 2) ? -11 : 211);
3650 Particle* newDaughters = particles.appendNew(d);
3651 daughterIndices_2.push_back(newDaughters->getArrayIndex());
3652 daughterMomenta_2.push_back(mom);
3653 momentum_2 = momentum_2 + mom;
3654
3655 auto* mcParticle = mcParticles.appendNew();
3656 mcParticle->setPDG((i % 2) ? -Const::electron.getPDGCode() : Const::pion.getPDGCode());
3658 mcParticle->set4Vector(mom);
3659 newDaughters->addRelationTo(mcParticle);
3660 }
3661
3662 const Particle* compositeDau_2 = particles.appendNew(momentum_2, 411, Particle::c_Flavored, daughterIndices_2);
3663 auto* mcCompositeDau_2 = mcParticles.appendNew();
3664 mcCompositeDau_2->setPDG(411);
3665 mcCompositeDau_2->setStatus(MCParticle::c_PrimaryParticle);
3666 mcCompositeDau_2->set4Vector(momentum_2);
3667 compositeDau_2->addRelationTo(mcCompositeDau_2);
3668
3669 // make the composite particle
3670 std::vector<int> daughterIndices = {compositeDau_1->getArrayIndex(), compositeDau_2->getArrayIndex()};
3671 const Particle* p = particles.appendNew(momentum_2 + momentum_1, 111, Particle::c_Unflavored, daughterIndices);
3672
3673
3674 // Test mcDaughterAngle
3675 const Manager::Var* var = Manager::Instance().getVariable("mcDaughterAngle(0, 1)");
3676 double v_test = acos(momentum_1.Vect().Unit().Dot(momentum_2.Vect().Unit()));
3677 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), v_test);
3678
3679 var = Manager::Instance().getVariable("mcDaughterAngle(0:0, 1:0)");
3680 v_test = acos(daughterMomenta_1[0].Vect().Unit().Dot(daughterMomenta_2[0].Vect().Unit()));
3681 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), v_test);
3682
3683 var = Manager::Instance().getVariable("mcDaughterAngle( 1, -1)");
3684 EXPECT_B2WARNING(std::get<double>(var->function(p)));
3685 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3686
3687 var = Manager::Instance().getVariable("mcDaughterAngle(1, 0:1:0:0:1)");
3688 EXPECT_B2WARNING(std::get<double>(var->function(p)));
3689 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3690
3691 // Test mcDaughterDiffOf
3692 var = Manager::Instance().getVariable("mcDaughterDiffOf(0, 1, PDG)");
3693 ASSERT_NE(var, nullptr);
3694 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0);
3695
3696 var = Manager::Instance().getVariable("mcDaughterDiffOf(0, NOTINT, PDG)");
3697 ASSERT_NE(var, nullptr);
3698 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3699
3700 // Test azimuthal angle as well
3701 var = Manager::Instance().getVariable("mcDaughterDiffOf(0, 1, phi)");
3702 ASSERT_NE(var, nullptr);
3703 v_test = momentum_2.Phi() - momentum_1.Phi();
3704 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), v_test);
3705
3706 }
3707
3708 TEST_F(MetaVariableTest, varForFirstMCAncestorOfType)
3709 {
3711 StoreArray<MCParticle> mcParticles;
3712 StoreArray<Particle> particles;
3713 particles.registerInDataStore();
3714 mcParticles.registerInDataStore();
3715 particles.registerRelationTo(mcParticles);
3716 StoreObjPtr<ParticleList> DList("D0:vartest");
3717 DList.registerInDataStore();
3718 DList.create();
3719 DList->initialize(421, "D0:vartest");
3721 PxPyPzEVector momentum;
3722 PxPyPzEVector momentum_0;
3723 PxPyPzEVector momentum_1;
3724 std::vector<int> D_daughterIndices;
3725 std::vector<int> D_grandDaughterIndices_0;
3726 std::vector<int> D_grandDaughterIndices_1;
3727
3728
3729 // Create MC graph for D -> (K0s -> pi+ + pi-) (K0s -> pi+ + pi-)
3730 MCParticleGraph mcGraph;
3731
3733 MCParticleGraph::GraphParticle& mcg_d_0 = mcGraph.addParticle();
3734 MCParticleGraph::GraphParticle& mcg_d_1 = mcGraph.addParticle();
3735 MCParticleGraph::GraphParticle& mcg_gd_0_0 = mcGraph.addParticle();
3736 MCParticleGraph::GraphParticle& mcg_gd_0_1 = mcGraph.addParticle();
3737 MCParticleGraph::GraphParticle& mcg_gd_1_0 = mcGraph.addParticle();
3738 MCParticleGraph::GraphParticle& mcg_gd_1_1 = mcGraph.addParticle();
3739 MCParticleGraph::GraphParticle& mcg_not_child = mcGraph.addParticle();
3740
3741 mcg_m.setPDG(421);
3742 mcg_m.set4Vector(PxPyPzEVector(7, 7, 7, 7));
3743 mcg_d_0.setPDG(-Const::Kshort.getPDGCode());
3744 mcg_d_0.set4Vector(PxPyPzEVector(6, 6, 6, 6));
3745 mcg_d_1.setPDG(Const::Kshort.getPDGCode());
3746 mcg_d_1.set4Vector(PxPyPzEVector(5, 5, 5, 5));
3747 mcg_gd_0_0.setPDG(Const::pion.getPDGCode());
3748 mcg_gd_0_0.set4Vector(PxPyPzEVector(4, 4, 4, 4));
3749 mcg_gd_0_1.setPDG(-Const::pion.getPDGCode());
3750 mcg_gd_0_1.set4Vector(PxPyPzEVector(3, 3, 3, 3));
3751 mcg_gd_1_0.setPDG(Const::pion.getPDGCode());
3752 mcg_gd_1_0.set4Vector(PxPyPzEVector(2, 1, 2, 2));
3753 mcg_gd_1_1.setPDG(-Const::pion.getPDGCode());
3754 mcg_gd_1_1.set4Vector(PxPyPzEVector(1, 1, 1, 1));
3755 mcg_not_child.setPDG(Const::pion.getPDGCode());
3756 mcg_not_child.set4Vector(PxPyPzEVector(10, 10, 10, 10));
3757
3758 mcg_d_0.comesFrom(mcg_m);
3759 mcg_d_1.comesFrom(mcg_m);
3760 mcg_gd_0_0.comesFrom(mcg_d_0);
3761 mcg_gd_0_1.comesFrom(mcg_d_0);
3762 mcg_gd_1_0.comesFrom(mcg_d_1);
3763 mcg_gd_1_1.comesFrom(mcg_d_1);
3764
3765 mcGraph.generateList();
3766
3767 // Get MC Particles from StoreArray
3768 auto* mc_not_child = mcParticles[0];
3769 auto* mc_m = mcParticles[1];
3770 auto* mc_d_0 = mcParticles[2];
3771 auto* mc_d_1 = mcParticles[3];
3772 auto* mc_gd_0_0 = mcParticles[4];
3773 auto* mc_gd_0_1 = mcParticles[5];
3774 auto* mc_gd_1_0 = mcParticles[6];
3775 auto* mc_gd_1_1 = mcParticles[7];
3776
3777
3778 mc_m->setStatus(MCParticle::c_PrimaryParticle);
3779 mc_d_0->setStatus(MCParticle::c_PrimaryParticle);
3780 mc_d_1->setStatus(MCParticle::c_PrimaryParticle);
3781 mc_gd_0_0->setStatus(MCParticle::c_PrimaryParticle);
3782 mc_gd_0_1->setStatus(MCParticle::c_PrimaryParticle);
3783 mc_gd_1_0->setStatus(MCParticle::c_PrimaryParticle);
3784 mc_gd_1_1->setStatus(MCParticle::c_PrimaryParticle);
3785 mc_not_child->setStatus(MCParticle::c_PrimaryParticle);
3786
3787 // Creation of D decay: D->K0s(->pi pi) K0s(->pi pi)
3788
3789 const Particle* D_gd_0_0 = particles.appendNew(PxPyPzEVector(0.0, 1, 1, 1), 211);
3790 const Particle* D_gd_0_1 = particles.appendNew(PxPyPzEVector(1.0, 1, 1, 1), -211);
3791 const Particle* D_gd_1_0 = particles.appendNew(PxPyPzEVector(2.0, 1, 1, 1), 211);
3792 const Particle* D_gd_1_1 = particles.appendNew(PxPyPzEVector(3.0, 1, 1, 1), -211);
3793
3794 D_grandDaughterIndices_0.push_back(D_gd_0_0->getArrayIndex());
3795 D_grandDaughterIndices_0.push_back(D_gd_0_1->getArrayIndex());
3796 D_grandDaughterIndices_1.push_back(D_gd_1_0->getArrayIndex());
3797 D_grandDaughterIndices_1.push_back(D_gd_1_1->getArrayIndex());
3798 momentum_0 = D_gd_0_0->get4Vector() + D_gd_0_1->get4Vector();
3799 momentum_1 = D_gd_1_0->get4Vector() + D_gd_1_1->get4Vector();
3800
3801
3802 const Particle* D_d_0 = particles.appendNew(momentum_0, 310, Particle::c_Unflavored, D_grandDaughterIndices_0);
3803 const Particle* D_d_1 = particles.appendNew(momentum_1, 310, Particle::c_Unflavored, D_grandDaughterIndices_1);
3804
3805
3806 momentum = D_d_0->get4Vector() + D_d_1->get4Vector();
3807 D_daughterIndices.push_back(D_d_0->getArrayIndex());
3808 D_daughterIndices.push_back(D_d_1->getArrayIndex());
3809
3810 const Particle* D_m = particles.appendNew(momentum, 421, Particle::c_Unflavored, D_daughterIndices);
3811 DList->addParticle(D_m);
3812
3813 // Particle that is not an child
3814 const Particle* not_child = particles.appendNew(PxPyPzEVector(5.0, 1, 1, 1), 211);
3815
3816 // Particle that is not an child and doesn't have MC particle
3817 const Particle* not_child_2 = particles.appendNew(PxPyPzEVector(6.0, 1, 1, 1), 211);
3818
3819 // MC matching
3820 D_gd_0_0->addRelationTo(mc_gd_0_0);
3821 D_gd_0_1->addRelationTo(mc_gd_0_1);
3822 D_gd_1_0->addRelationTo(mc_gd_1_0);
3823 D_gd_1_1->addRelationTo(mc_gd_1_1);
3824 D_d_0->addRelationTo(mc_d_0);
3825 D_d_1->addRelationTo(mc_d_1);
3826 D_m->addRelationTo(mc_m);
3827 not_child->addRelationTo(mc_not_child);
3828
3829 // All pions should have common D mother
3830 const Manager::Var* var_d = Manager::Instance().getVariable("varForFirstMCAncestorOfType(D0, mdstIndex)");
3831 ASSERT_NE(var_d, nullptr);
3832 EXPECT_TRUE(std::get<double>(var_d->function(D_gd_0_0)) >= 0);
3833 EXPECT_FLOAT_EQ(std::get<double>(var_d->function(D_gd_0_0)), std::get<double>(var_d->function(D_gd_0_1)));
3834 EXPECT_FLOAT_EQ(std::get<double>(var_d->function(D_gd_1_0)), std::get<double>(var_d->function(D_gd_1_1)));
3835 EXPECT_FLOAT_EQ(std::get<double>(var_d->function(D_gd_0_0)), std::get<double>(var_d->function(D_gd_1_0)));
3836 EXPECT_FLOAT_EQ(std::get<double>(var_d->function(D_gd_0_1)), std::get<double>(var_d->function(D_gd_1_1)));
3837 EXPECT_TRUE(std::isnan(std::get<double>(var_d->function(not_child))));
3838 EXPECT_TRUE(std::isnan(std::get<double>(var_d->function(not_child_2))));
3839
3840
3841 // // All but they have different K0s mothers
3842 const Manager::Var* var_310 = Manager::Instance().getVariable("varForFirstMCAncestorOfType(310, mdstIndex)");
3843 ASSERT_NE(var_310, nullptr);
3844 EXPECT_FLOAT_EQ(std::get<double>(var_310->function(D_gd_0_0)), std::get<double>(var_310->function(D_gd_0_1)));
3845 EXPECT_FLOAT_EQ(std::get<double>(var_310->function(D_gd_1_0)), std::get<double>(var_310->function(D_gd_1_1)));
3846 EXPECT_NE(std::get<double>(var_310->function(D_gd_0_0)), std::get<double>(var_310->function(D_gd_1_0)));
3847 EXPECT_NE(std::get<double>(var_310->function(D_gd_0_1)), std::get<double>(var_310->function(D_gd_1_1)));
3848 EXPECT_TRUE(std::isnan(std::get<double>(var_310->function(not_child))));
3849 EXPECT_TRUE(std::isnan(std::get<double>(var_310->function(not_child_2))));
3850 EXPECT_FLOAT_EQ(int(std::get<double>(Manager::Instance().getVariable("varForFirstMCAncestorOfType(310, E)")->function(D_gd_0_0))),
3851 10);
3852 }
3853
3854 TEST_F(MetaVariableTest, isDescendantOfList)
3855 {
3857 StoreObjPtr<ParticleList> DList("D0:vartest");
3858 DList.registerInDataStore();
3859 DList.create();
3860 DList->initialize(421, "D0:vartest");
3861 StoreObjPtr<ParticleList> BList("B:vartest");
3862 BList.registerInDataStore();
3863 BList.create();
3864 BList->initialize(521, "B:vartest");
3866
3867 PxPyPzEVector momentum;
3868 PxPyPzEVector momentum_0;
3869 PxPyPzEVector momentum_1;
3870 StoreArray<Particle> particles;
3871 std::vector<int> D_daughterIndices;
3872 std::vector<int> D_grandDaughterIndices_0;
3873 std::vector<int> D_grandDaughterIndices_1;
3874 std::vector<int> B_daughterIndices;
3875 std::vector<int> B_grandDaughterIndices;
3876 std::vector<int> B_grandGrandDaughterIndices;
3877
3878 // Creation of D decay: D->K0s(->pi pi) K0s(->pi pi)
3879
3880 const Particle* D_gd_0_0 = particles.appendNew(PxPyPzEVector(0.0, 1, 1, 1), 211, Particle::c_Flavored, Particle::c_Track, 0);
3881 const Particle* D_gd_0_1 = particles.appendNew(PxPyPzEVector(1.0, 1, 1, 1), -211, Particle::c_Flavored, Particle::c_Track, 1);
3882 const Particle* D_gd_1_0 = particles.appendNew(PxPyPzEVector(2.0, 1, 1, 1), 211, Particle::c_Flavored, Particle::c_Track, 2);
3883 const Particle* D_gd_1_1 = particles.appendNew(PxPyPzEVector(3.0, 1, 1, 1), -211, Particle::c_Flavored, Particle::c_Track, 3);
3884
3885 D_grandDaughterIndices_0.push_back(D_gd_0_0->getArrayIndex());
3886 D_grandDaughterIndices_0.push_back(D_gd_0_1->getArrayIndex());
3887 D_grandDaughterIndices_1.push_back(D_gd_1_0->getArrayIndex());
3888 D_grandDaughterIndices_1.push_back(D_gd_1_1->getArrayIndex());
3889 momentum_0 = D_gd_0_0->get4Vector() + D_gd_0_1->get4Vector();
3890 momentum_1 = D_gd_1_0->get4Vector() + D_gd_1_1->get4Vector();
3891
3892
3893 const Particle* D_d_0 = particles.appendNew(momentum_0, 310, Particle::c_Unflavored, D_grandDaughterIndices_0);
3894 const Particle* D_d_1 = particles.appendNew(momentum_1, 310, Particle::c_Unflavored, D_grandDaughterIndices_1);
3895
3896
3897 momentum = D_d_0->get4Vector() + D_d_1->get4Vector();
3898 D_daughterIndices.push_back(D_d_0->getArrayIndex());
3899 D_daughterIndices.push_back(D_d_1->getArrayIndex());
3900
3901 const Particle* D_m = particles.appendNew(momentum, 421, Particle::c_Unflavored, D_daughterIndices);
3902 DList->addParticle(D_m);
3903
3904 // Creation of B decay B -> D(->K0s(->pi pi) pi) pi
3905
3906 const Particle* B_d_1 = particles.appendNew(PxPyPzEVector(0.0, 1, 1, 1), 211, Particle::c_Flavored, Particle::c_Track, 4);
3907 const Particle* B_gd_0_1 = particles.appendNew(PxPyPzEVector(1.0, 1, 1, 1), -211, Particle::c_Flavored, Particle::c_Track, 5);
3908 const Particle* B_ggd_0_0_0 = particles.appendNew(PxPyPzEVector(2.0, 1, 1, 1), 211, Particle::c_Flavored, Particle::c_Track, 6);
3909 const Particle* B_ggd_0_0_1 = particles.appendNew(PxPyPzEVector(3.0, 1, 1, 1), -211, Particle::c_Flavored, Particle::c_Track, 7);
3910
3911 B_grandGrandDaughterIndices.push_back(B_ggd_0_0_0->getArrayIndex());
3912 B_grandGrandDaughterIndices.push_back(B_ggd_0_0_1->getArrayIndex());
3913 momentum_0 = B_ggd_0_0_0->get4Vector() + B_ggd_0_0_1->get4Vector();
3914 const Particle* B_gd_0_0 = particles.appendNew(momentum_0, 310, Particle::c_Unflavored, B_grandGrandDaughterIndices);
3915
3916 B_grandDaughterIndices.push_back(B_gd_0_0->getArrayIndex());
3917 B_grandDaughterIndices.push_back(B_gd_0_1->getArrayIndex());
3918 momentum_1 = B_gd_0_0->get4Vector() + B_gd_0_1->get4Vector();
3919 const Particle* B_d_0 = particles.appendNew(momentum_1, -411, Particle::c_Unflavored, B_grandDaughterIndices);
3920
3921 B_daughterIndices.push_back(B_d_0->getArrayIndex());
3922 B_daughterIndices.push_back(B_d_1->getArrayIndex());
3923 momentum = B_d_0->get4Vector() + B_d_1->get4Vector();
3924 const Particle* B_m = particles.appendNew(momentum, 521, Particle::c_Unflavored, B_daughterIndices);
3925 BList->addParticle(B_m);
3926
3927 // Particle that is not an child
3928 const Particle* not_child = particles.appendNew(PxPyPzEVector(5.0, 1, 1, 1), 211, Particle::c_Flavored, Particle::c_Track, 8);
3929
3930
3931 const Manager::Var* var_0 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest)");
3932 ASSERT_NE(var_0, nullptr);
3933 EXPECT_TRUE(std::get<bool>(var_0->function(D_gd_0_0)));
3934 EXPECT_TRUE(std::get<bool>(var_0->function(D_gd_0_1)));
3935 EXPECT_TRUE(std::get<bool>(var_0->function(D_gd_1_0)));
3936 EXPECT_TRUE(std::get<bool>(var_0->function(D_gd_1_1)));
3937 EXPECT_TRUE(std::get<bool>(var_0->function(D_d_0)));
3938 EXPECT_TRUE(std::get<bool>(var_0->function(D_d_1)));
3939 EXPECT_FALSE(std::get<bool>(var_0->function(B_ggd_0_0_0)));
3940 EXPECT_FALSE(std::get<bool>(var_0->function(B_ggd_0_0_1)));
3941 EXPECT_FALSE(std::get<bool>(var_0->function(B_gd_0_0)));
3942 EXPECT_FALSE(std::get<bool>(var_0->function(B_gd_0_1)));
3943 EXPECT_FALSE(std::get<bool>(var_0->function(B_d_0)));
3944 EXPECT_FALSE(std::get<bool>(var_0->function(B_d_1)));
3945 EXPECT_FALSE(std::get<bool>(var_0->function(not_child)));
3946
3947 const Manager::Var* var_0a = Manager::Instance().getVariable("isDaughterOfList(D0:vartest)");
3948 ASSERT_NE(var_0a, nullptr);
3949 EXPECT_FALSE(std::get<bool>(var_0a->function(D_gd_0_0)));
3950 EXPECT_FALSE(std::get<bool>(var_0a->function(D_gd_0_1)));
3951 EXPECT_FALSE(std::get<bool>(var_0a->function(D_gd_1_0)));
3952 EXPECT_FALSE(std::get<bool>(var_0a->function(D_gd_1_1)));
3953 EXPECT_TRUE(std::get<bool>(var_0a->function(D_d_0)));
3954 EXPECT_TRUE(std::get<bool>(var_0a->function(D_d_1)));
3955 EXPECT_FALSE(std::get<bool>(var_0a->function(B_ggd_0_0_0)));
3956 EXPECT_FALSE(std::get<bool>(var_0a->function(B_ggd_0_0_1)));
3957 EXPECT_FALSE(std::get<bool>(var_0a->function(B_gd_0_0)));
3958 EXPECT_FALSE(std::get<bool>(var_0a->function(B_gd_0_1)));
3959 EXPECT_FALSE(std::get<bool>(var_0a->function(B_d_0)));
3960 EXPECT_FALSE(std::get<bool>(var_0a->function(B_d_1)));
3961 EXPECT_FALSE(std::get<bool>(var_0a->function(not_child)));
3962
3963 const Manager::Var* var_0b = Manager::Instance().getVariable("isGrandDaughterOfList(D0:vartest)");
3964 ASSERT_NE(var_0b, nullptr);
3965 EXPECT_TRUE(std::get<bool>(var_0b->function(D_gd_0_0)));
3966 EXPECT_TRUE(std::get<bool>(var_0b->function(D_gd_0_1)));
3967 EXPECT_TRUE(std::get<bool>(var_0b->function(D_gd_1_0)));
3968 EXPECT_TRUE(std::get<bool>(var_0b->function(D_gd_1_1)));
3969 EXPECT_FALSE(std::get<bool>(var_0b->function(D_d_0)));
3970 EXPECT_FALSE(std::get<bool>(var_0b->function(D_d_1)));
3971 EXPECT_FALSE(std::get<bool>(var_0b->function(B_ggd_0_0_0)));
3972 EXPECT_FALSE(std::get<bool>(var_0b->function(B_ggd_0_0_1)));
3973 EXPECT_FALSE(std::get<bool>(var_0b->function(B_gd_0_0)));
3974 EXPECT_FALSE(std::get<bool>(var_0b->function(B_gd_0_1)));
3975 EXPECT_FALSE(std::get<bool>(var_0b->function(B_d_0)));
3976 EXPECT_FALSE(std::get<bool>(var_0b->function(B_d_1)));
3977 EXPECT_FALSE(std::get<bool>(var_0b->function(not_child)));
3978
3979 const Manager::Var* var_1 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest, 1)");
3980 ASSERT_NE(var_1, nullptr);
3981 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_0_0)));
3982 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_0_1)));
3983 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_1_0)));
3984 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_1_1)));
3985 EXPECT_TRUE(std::get<bool>(var_1->function(D_d_0)));
3986 EXPECT_TRUE(std::get<bool>(var_1->function(D_d_1)));
3987 EXPECT_FALSE(std::get<bool>(var_1->function(B_ggd_0_0_0)));
3988 EXPECT_FALSE(std::get<bool>(var_1->function(B_ggd_0_0_1)));
3989 EXPECT_FALSE(std::get<bool>(var_1->function(B_gd_0_0)));
3990 EXPECT_FALSE(std::get<bool>(var_1->function(B_gd_0_1)));
3991 EXPECT_FALSE(std::get<bool>(var_1->function(B_d_0)));
3992 EXPECT_FALSE(std::get<bool>(var_1->function(B_d_1)));
3993 EXPECT_FALSE(std::get<bool>(var_1->function(not_child)));
3994
3995 const Manager::Var* var_2 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest, 2)");
3996 ASSERT_NE(var_2, nullptr);
3997 EXPECT_TRUE(std::get<bool>(var_2->function(D_gd_0_0)));
3998 EXPECT_TRUE(std::get<bool>(var_2->function(D_gd_0_1)));
3999 EXPECT_TRUE(std::get<bool>(var_2->function(D_gd_1_0)));
4000 EXPECT_TRUE(std::get<bool>(var_2->function(D_gd_1_1)));
4001 EXPECT_FALSE(std::get<bool>(var_2->function(D_d_0)));
4002 EXPECT_FALSE(std::get<bool>(var_2->function(D_d_1)));
4003 EXPECT_FALSE(std::get<bool>(var_2->function(B_ggd_0_0_0)));
4004 EXPECT_FALSE(std::get<bool>(var_2->function(B_ggd_0_0_1)));
4005 EXPECT_FALSE(std::get<bool>(var_2->function(B_gd_0_0)));
4006 EXPECT_FALSE(std::get<bool>(var_2->function(B_gd_0_1)));
4007 EXPECT_FALSE(std::get<bool>(var_2->function(B_d_0)));
4008 EXPECT_FALSE(std::get<bool>(var_2->function(B_d_1)));
4009 EXPECT_FALSE(std::get<bool>(var_2->function(not_child)));
4010
4011 const Manager::Var* var_3 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest, B:vartest)");
4012 ASSERT_NE(var_3, nullptr);
4013 EXPECT_TRUE(std::get<bool>(var_3->function(D_gd_0_0)));
4014 EXPECT_TRUE(std::get<bool>(var_3->function(D_gd_0_1)));
4015 EXPECT_TRUE(std::get<bool>(var_3->function(D_gd_1_0)));
4016 EXPECT_TRUE(std::get<bool>(var_3->function(D_gd_1_1)));
4017 EXPECT_TRUE(std::get<bool>(var_3->function(D_d_0)));
4018 EXPECT_TRUE(std::get<bool>(var_3->function(D_d_1)));
4019 EXPECT_TRUE(std::get<bool>(var_3->function(B_ggd_0_0_0)));
4020 EXPECT_TRUE(std::get<bool>(var_3->function(B_ggd_0_0_1)));
4021 EXPECT_TRUE(std::get<bool>(var_3->function(B_gd_0_0)));
4022 EXPECT_TRUE(std::get<bool>(var_3->function(B_gd_0_1)));
4023 EXPECT_TRUE(std::get<bool>(var_3->function(B_d_0)));
4024 EXPECT_TRUE(std::get<bool>(var_3->function(B_d_1)));
4025 EXPECT_FALSE(std::get<bool>(var_3->function(not_child)));
4026
4027 const Manager::Var* var_4 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest, B:vartest, -1)");
4028 ASSERT_NE(var_4, nullptr);
4029 EXPECT_TRUE(std::get<bool>(var_4->function(D_gd_0_0)));
4030 EXPECT_TRUE(std::get<bool>(var_4->function(D_gd_0_1)));
4031 EXPECT_TRUE(std::get<bool>(var_4->function(D_gd_1_0)));
4032 EXPECT_TRUE(std::get<bool>(var_4->function(D_gd_1_1)));
4033 EXPECT_TRUE(std::get<bool>(var_4->function(D_d_0)));
4034 EXPECT_TRUE(std::get<bool>(var_4->function(D_d_1)));
4035 EXPECT_TRUE(std::get<bool>(var_4->function(B_ggd_0_0_0)));
4036 EXPECT_TRUE(std::get<bool>(var_4->function(B_ggd_0_0_1)));
4037 EXPECT_TRUE(std::get<bool>(var_4->function(B_gd_0_0)));
4038 EXPECT_TRUE(std::get<bool>(var_4->function(B_gd_0_1)));
4039 EXPECT_TRUE(std::get<bool>(var_4->function(B_d_0)));
4040 EXPECT_TRUE(std::get<bool>(var_4->function(B_d_1)));
4041 EXPECT_FALSE(std::get<bool>(var_4->function(not_child)));
4042
4043 const Manager::Var* var_5 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest, B:vartest, 1)");
4044 ASSERT_NE(var_5, nullptr);
4045 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_0_0)));
4046 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_0_1)));
4047 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_1_0)));
4048 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_1_1)));
4049 EXPECT_TRUE(std::get<bool>(var_5->function(D_d_0)));
4050 EXPECT_TRUE(std::get<bool>(var_5->function(D_d_1)));
4051 EXPECT_FALSE(std::get<bool>(var_5->function(B_ggd_0_0_0)));
4052 EXPECT_FALSE(std::get<bool>(var_5->function(B_ggd_0_0_1)));
4053 EXPECT_FALSE(std::get<bool>(var_5->function(B_gd_0_0)));
4054 EXPECT_FALSE(std::get<bool>(var_5->function(B_gd_0_1)));
4055 EXPECT_TRUE(std::get<bool>(var_5->function(B_d_0)));
4056 EXPECT_TRUE(std::get<bool>(var_5->function(B_d_1)));
4057 EXPECT_FALSE(std::get<bool>(var_5->function(not_child)));
4058
4059 const Manager::Var* var_6 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest, B:vartest, 2)");
4060 ASSERT_NE(var_6, nullptr);
4061 EXPECT_TRUE(std::get<bool>(var_6->function(D_gd_0_0)));
4062 EXPECT_TRUE(std::get<bool>(var_6->function(D_gd_0_1)));
4063 EXPECT_TRUE(std::get<bool>(var_6->function(D_gd_1_0)));
4064 EXPECT_TRUE(std::get<bool>(var_6->function(D_gd_1_1)));
4065 EXPECT_FALSE(std::get<bool>(var_6->function(D_d_0)));
4066 EXPECT_FALSE(std::get<bool>(var_6->function(D_d_1)));
4067 EXPECT_FALSE(std::get<bool>(var_6->function(B_ggd_0_0_0)));
4068 EXPECT_FALSE(std::get<bool>(var_6->function(B_ggd_0_0_1)));
4069 EXPECT_TRUE(std::get<bool>(var_6->function(B_gd_0_0)));
4070 EXPECT_TRUE(std::get<bool>(var_6->function(B_gd_0_1)));
4071 EXPECT_FALSE(std::get<bool>(var_6->function(B_d_0)));
4072 EXPECT_FALSE(std::get<bool>(var_6->function(B_d_1)));
4073 EXPECT_FALSE(std::get<bool>(var_6->function(not_child)));
4074
4075 const Manager::Var* var_7 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest, B:vartest, 3)");
4076 ASSERT_NE(var_7, nullptr);
4077 EXPECT_FALSE(std::get<bool>(var_7->function(D_gd_0_0)));
4078 EXPECT_FALSE(std::get<bool>(var_7->function(D_gd_0_1)));
4079 EXPECT_FALSE(std::get<bool>(var_7->function(D_gd_1_0)));
4080 EXPECT_FALSE(std::get<bool>(var_7->function(D_gd_1_1)));
4081 EXPECT_FALSE(std::get<bool>(var_7->function(D_d_0)));
4082 EXPECT_FALSE(std::get<bool>(var_7->function(D_d_1)));
4083 EXPECT_TRUE(std::get<bool>(var_7->function(B_ggd_0_0_0)));
4084 EXPECT_TRUE(std::get<bool>(var_7->function(B_ggd_0_0_1)));
4085 EXPECT_FALSE(std::get<bool>(var_7->function(B_gd_0_0)));
4086 EXPECT_FALSE(std::get<bool>(var_7->function(B_gd_0_1)));
4087 EXPECT_FALSE(std::get<bool>(var_7->function(B_d_0)));
4088 EXPECT_FALSE(std::get<bool>(var_7->function(B_d_1)));
4089 EXPECT_FALSE(std::get<bool>(var_7->function(not_child)));
4090 }
4091
4092
4093 TEST_F(MetaVariableTest, isMCDescendantOfList)
4094 {
4096 StoreArray<MCParticle> mcParticles;
4097 StoreArray<Particle> particles;
4098 particles.registerInDataStore();
4099 mcParticles.registerInDataStore();
4100 particles.registerRelationTo(mcParticles);
4101 StoreObjPtr<ParticleList> BList("B:vartest");
4102 BList.registerInDataStore();
4103 BList.create();
4104 BList->initialize(521, "B:vartest");
4105 StoreObjPtr<ParticleList> DList("D0:vartest");
4106 DList.registerInDataStore();
4107 DList.create();
4108 DList->initialize(421, "D0:vartest");
4110 PxPyPzEVector momentum;
4111 PxPyPzEVector momentum_0;
4112 PxPyPzEVector momentum_1;
4113 std::vector<int> daughterIndices;
4114 std::vector<int> grandDaughterIndices;
4115 std::vector<int> grandGrandDaughterIndices;
4116 std::vector<int> D_daughterIndices;
4117 std::vector<int> D_grandDaughterIndices_0;
4118 std::vector<int> D_grandDaughterIndices_1;
4119
4120
4121 // Create MC graph for B+ -> (D -> (K0s -> pi+ + pi-) pi-) + pi+
4122 MCParticleGraph mcGraph;
4123
4125 MCParticleGraph::GraphParticle& mcg_d_0 = mcGraph.addParticle();
4126 MCParticleGraph::GraphParticle& mcg_d_1 = mcGraph.addParticle();
4127 MCParticleGraph::GraphParticle& mcg_gd_0_0 = mcGraph.addParticle();
4128 MCParticleGraph::GraphParticle& mcg_gd_0_1 = mcGraph.addParticle();
4129 MCParticleGraph::GraphParticle& mcg_ggd_0_0_0 = mcGraph.addParticle();
4130 MCParticleGraph::GraphParticle& mcg_ggd_0_0_1 = mcGraph.addParticle();
4131 MCParticleGraph::GraphParticle& mcg_not_child = mcGraph.addParticle();
4132
4133 mcg_m.setPDG(521);
4134 mcg_d_0.setPDG(-411);
4135 mcg_d_1.setPDG(Const::pion.getPDGCode());
4136 mcg_gd_0_0.setPDG(Const::Kshort.getPDGCode());
4137 mcg_gd_0_1.setPDG(-Const::pion.getPDGCode());
4138 mcg_ggd_0_0_0.setPDG(Const::pion.getPDGCode());
4139 mcg_ggd_0_0_1.setPDG(-Const::pion.getPDGCode());
4140 mcg_not_child.setPDG(Const::pion.getPDGCode());
4141
4142 mcg_d_0.comesFrom(mcg_m);
4143 mcg_d_1.comesFrom(mcg_m);
4144 mcg_gd_0_0.comesFrom(mcg_d_0);
4145 mcg_gd_0_1.comesFrom(mcg_d_0);
4146 mcg_ggd_0_0_0.comesFrom(mcg_gd_0_1);
4147 mcg_ggd_0_0_1.comesFrom(mcg_gd_0_1);
4148
4149 mcGraph.generateList();
4150
4151 // Get MC Particles from StoreArray
4152 auto* mc_m = mcParticles[0];
4153 auto* mc_d_0 = mcParticles[1];
4154 auto* mc_d_1 = mcParticles[2];
4155 auto* mc_gd_0_0 = mcParticles[3];
4156 auto* mc_gd_0_1 = mcParticles[4];
4157 auto* mc_ggd_0_0_0 = mcParticles[5];
4158 auto* mc_ggd_0_0_1 = mcParticles[6];
4159 auto* mc_not_child = mcParticles[7];
4160
4161 mc_m->setStatus(MCParticle::c_PrimaryParticle);
4162 mc_d_0->setStatus(MCParticle::c_PrimaryParticle);
4163 mc_d_1->setStatus(MCParticle::c_PrimaryParticle);
4164 mc_gd_0_0->setStatus(MCParticle::c_PrimaryParticle);
4165 mc_gd_0_1->setStatus(MCParticle::c_PrimaryParticle);
4166 mc_ggd_0_0_0->setStatus(MCParticle::c_PrimaryParticle);
4167 mc_ggd_0_0_1->setStatus(MCParticle::c_PrimaryParticle);
4168 mc_not_child->setStatus(MCParticle::c_PrimaryParticle);
4169
4170 // Creation of D decay: D->K0s(->pi pi) K0s(->pi pi) (not matched)
4171
4172 const Particle* D_gd_0_0 = particles.appendNew(PxPyPzEVector(0.0, 1, 1, 1), 211);
4173 const Particle* D_gd_0_1 = particles.appendNew(PxPyPzEVector(1.0, 1, 1, 1), -211);
4174 const Particle* D_gd_1_0 = particles.appendNew(PxPyPzEVector(2.0, 1, 1, 1), 211);
4175 const Particle* D_gd_1_1 = particles.appendNew(PxPyPzEVector(3.0, 1, 1, 1), -211);
4176
4177 D_grandDaughterIndices_0.push_back(D_gd_0_0->getArrayIndex());
4178 D_grandDaughterIndices_0.push_back(D_gd_0_1->getArrayIndex());
4179 D_grandDaughterIndices_1.push_back(D_gd_1_0->getArrayIndex());
4180 D_grandDaughterIndices_1.push_back(D_gd_1_1->getArrayIndex());
4181 momentum_0 = D_gd_0_0->get4Vector() + D_gd_0_1->get4Vector();
4182 momentum_1 = D_gd_1_0->get4Vector() + D_gd_1_1->get4Vector();
4183
4184
4185 const Particle* D_d_0 = particles.appendNew(momentum_0, 310, Particle::c_Unflavored, D_grandDaughterIndices_0);
4186 const Particle* D_d_1 = particles.appendNew(momentum_1, 310, Particle::c_Unflavored, D_grandDaughterIndices_1);
4187
4188
4189 momentum = D_d_0->get4Vector() + D_d_1->get4Vector();
4190 D_daughterIndices.push_back(D_d_0->getArrayIndex());
4191 D_daughterIndices.push_back(D_d_1->getArrayIndex());
4192
4193 const Particle* D_m = particles.appendNew(momentum, 421, Particle::c_Unflavored, D_daughterIndices);
4194 DList->addParticle(D_m);
4195
4196 // Creating B decay
4197 const Particle* d_1 = particles.appendNew(PxPyPzEVector(0.0, 1, 1, 1), 211);
4198 const Particle* gd_0_1 = particles.appendNew(PxPyPzEVector(1.0, 1, 1, 1), -211);
4199 const Particle* ggd_0_0_0 = particles.appendNew(PxPyPzEVector(2.0, 1, 1, 1), 211);
4200 const Particle* ggd_0_0_1 = particles.appendNew(PxPyPzEVector(3.0, 1, 1, 1), -211);
4201
4202 grandGrandDaughterIndices.push_back(ggd_0_0_0->getArrayIndex());
4203 grandGrandDaughterIndices.push_back(ggd_0_0_1->getArrayIndex());
4204 momentum_0 = ggd_0_0_0->get4Vector() + ggd_0_0_1->get4Vector();
4205 const Particle* gd_0_0 = particles.appendNew(momentum_0, 310, Particle::c_Unflavored, grandGrandDaughterIndices);
4206
4207 grandDaughterIndices.push_back(gd_0_0->getArrayIndex());
4208 grandDaughterIndices.push_back(gd_0_1->getArrayIndex());
4209 momentum_1 = gd_0_0->get4Vector() + gd_0_1->get4Vector();
4210 const Particle* d_0 = particles.appendNew(momentum_1, -411, Particle::c_Unflavored, grandDaughterIndices);
4211
4212 daughterIndices.push_back(d_0->getArrayIndex());
4213 daughterIndices.push_back(d_1->getArrayIndex());
4214 momentum = d_0->get4Vector() + d_1->get4Vector();
4215 const Particle* m = particles.appendNew(momentum, 521, Particle::c_Unflavored, daughterIndices);
4216 BList->addParticle(m);
4217
4218 // Particle that is not an child
4219 const Particle* not_child = particles.appendNew(PxPyPzEVector(5.0, 1, 1, 1), 211);
4220
4221 // Particle that is not an child and doesn't have MC particle
4222 const Particle* not_child_2 = particles.appendNew(PxPyPzEVector(6.0, 1, 1, 1), 211);
4223
4224 gd_0_0->addRelationTo(mc_gd_0_0);
4225 gd_0_1->addRelationTo(mc_gd_0_1);
4226 ggd_0_0_0->addRelationTo(mc_ggd_0_0_0);
4227 ggd_0_0_1->addRelationTo(mc_ggd_0_0_1);
4228 d_0->addRelationTo(mc_d_0);
4229 d_1->addRelationTo(mc_d_1);
4230 m->addRelationTo(mc_m);
4231 not_child->addRelationTo(mc_not_child);
4232
4233 const Manager::Var* var_0 = Manager::Instance().getVariable("isMCDescendantOfList(B:vartest)");
4234 ASSERT_NE(var_0, nullptr);
4235 EXPECT_FALSE(std::get<bool>(var_0->function(D_gd_0_0)));
4236 EXPECT_FALSE(std::get<bool>(var_0->function(D_gd_0_1)));
4237 EXPECT_FALSE(std::get<bool>(var_0->function(D_gd_1_0)));
4238 EXPECT_FALSE(std::get<bool>(var_0->function(D_gd_1_1)));
4239 EXPECT_FALSE(std::get<bool>(var_0->function(D_d_0)));
4240 EXPECT_FALSE(std::get<bool>(var_0->function(D_d_1)));
4241 EXPECT_TRUE(std::get<bool>(var_0->function(ggd_0_0_0)));
4242 EXPECT_TRUE(std::get<bool>(var_0->function(ggd_0_0_1)));
4243 EXPECT_TRUE(std::get<bool>(var_0->function(gd_0_0)));
4244 EXPECT_TRUE(std::get<bool>(var_0->function(gd_0_1)));
4245 EXPECT_TRUE(std::get<bool>(var_0->function(d_0)));
4246 EXPECT_TRUE(std::get<bool>(var_0->function(d_1)));
4247 EXPECT_FALSE(std::get<bool>(var_0->function(not_child)));
4248 EXPECT_FALSE(std::get<bool>(var_0->function(not_child_2)));
4249
4250 const Manager::Var* var_1 = Manager::Instance().getVariable("isMCDescendantOfList(B:vartest, D0:vartest)");
4251 ASSERT_NE(var_1, nullptr);
4252 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_0_0)));
4253 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_0_1)));
4254 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_1_0)));
4255 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_1_1)));
4256 EXPECT_FALSE(std::get<bool>(var_1->function(D_d_0)));
4257 EXPECT_FALSE(std::get<bool>(var_1->function(D_d_1)));
4258 EXPECT_TRUE(std::get<bool>(var_1->function(ggd_0_0_0)));
4259 EXPECT_TRUE(std::get<bool>(var_1->function(ggd_0_0_1)));
4260 EXPECT_TRUE(std::get<bool>(var_1->function(gd_0_0)));
4261 EXPECT_TRUE(std::get<bool>(var_1->function(gd_0_1)));
4262 EXPECT_TRUE(std::get<bool>(var_1->function(d_0)));
4263 EXPECT_TRUE(std::get<bool>(var_1->function(d_1)));
4264 EXPECT_FALSE(std::get<bool>(var_1->function(not_child)));
4265 EXPECT_FALSE(std::get<bool>(var_1->function(not_child_2)));
4266
4267 const Manager::Var* var_2 = Manager::Instance().getVariable("isMCDescendantOfList(B:vartest, -1)");
4268 ASSERT_NE(var_2, nullptr);
4269 EXPECT_FALSE(std::get<bool>(var_2->function(D_gd_0_0)));
4270 EXPECT_FALSE(std::get<bool>(var_2->function(D_gd_0_1)));
4271 EXPECT_FALSE(std::get<bool>(var_2->function(D_gd_1_0)));
4272 EXPECT_FALSE(std::get<bool>(var_2->function(D_gd_1_1)));
4273 EXPECT_FALSE(std::get<bool>(var_2->function(D_d_0)));
4274 EXPECT_FALSE(std::get<bool>(var_2->function(D_d_1)));
4275 EXPECT_TRUE(std::get<bool>(var_2->function(ggd_0_0_0)));
4276 EXPECT_TRUE(std::get<bool>(var_2->function(ggd_0_0_1)));
4277 EXPECT_TRUE(std::get<bool>(var_2->function(gd_0_0)));
4278 EXPECT_TRUE(std::get<bool>(var_2->function(gd_0_1)));
4279 EXPECT_TRUE(std::get<bool>(var_2->function(d_0)));
4280 EXPECT_TRUE(std::get<bool>(var_2->function(d_1)));
4281 EXPECT_FALSE(std::get<bool>(var_2->function(not_child)));
4282 EXPECT_FALSE(std::get<bool>(var_2->function(not_child_2)));
4283
4284 const Manager::Var* var_3 = Manager::Instance().getVariable("isMCDescendantOfList(B:vartest, 1)");
4285 ASSERT_NE(var_3, nullptr);
4286 EXPECT_FALSE(std::get<bool>(var_3->function(D_gd_0_0)));
4287 EXPECT_FALSE(std::get<bool>(var_3->function(D_gd_0_1)));
4288 EXPECT_FALSE(std::get<bool>(var_3->function(D_gd_1_0)));
4289 EXPECT_FALSE(std::get<bool>(var_3->function(D_gd_1_1)));
4290 EXPECT_FALSE(std::get<bool>(var_3->function(D_d_0)));
4291 EXPECT_FALSE(std::get<bool>(var_3->function(D_d_1)));
4292 EXPECT_FALSE(std::get<bool>(var_3->function(ggd_0_0_0)));
4293 EXPECT_FALSE(std::get<bool>(var_3->function(ggd_0_0_1)));
4294 EXPECT_FALSE(std::get<bool>(var_3->function(gd_0_0)));
4295 EXPECT_FALSE(std::get<bool>(var_3->function(gd_0_1)));
4296 EXPECT_TRUE(std::get<bool>(var_3->function(d_0)));
4297 EXPECT_TRUE(std::get<bool>(var_3->function(d_1)));
4298 EXPECT_FALSE(std::get<bool>(var_3->function(not_child)));
4299 EXPECT_FALSE(std::get<bool>(var_3->function(not_child_2)));
4300
4301 const Manager::Var* var_4 = Manager::Instance().getVariable("isMCDescendantOfList(B:vartest, 2)");
4302 ASSERT_NE(var_4, nullptr);
4303 EXPECT_FALSE(std::get<bool>(var_4->function(D_gd_0_0)));
4304 EXPECT_FALSE(std::get<bool>(var_4->function(D_gd_0_1)));
4305 EXPECT_FALSE(std::get<bool>(var_4->function(D_gd_1_0)));
4306 EXPECT_FALSE(std::get<bool>(var_4->function(D_gd_1_1)));
4307 EXPECT_FALSE(std::get<bool>(var_4->function(D_d_0)));
4308 EXPECT_FALSE(std::get<bool>(var_4->function(D_d_1)));
4309 EXPECT_FALSE(std::get<bool>(var_4->function(ggd_0_0_0)));
4310 EXPECT_FALSE(std::get<bool>(var_4->function(ggd_0_0_1)));
4311 EXPECT_TRUE(std::get<bool>(var_4->function(gd_0_0)));
4312 EXPECT_TRUE(std::get<bool>(var_4->function(gd_0_1)));
4313 EXPECT_FALSE(std::get<bool>(var_4->function(d_0)));
4314 EXPECT_FALSE(std::get<bool>(var_4->function(d_1)));
4315 EXPECT_FALSE(std::get<bool>(var_4->function(not_child)));
4316 EXPECT_FALSE(std::get<bool>(var_4->function(not_child_2)));
4317
4318
4319 const Manager::Var* var_5 = Manager::Instance().getVariable("isMCDescendantOfList(B:vartest, 3)");
4320 ASSERT_NE(var_5, nullptr);
4321 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_0_0)));
4322 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_0_1)));
4323 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_1_0)));
4324 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_1_1)));
4325 EXPECT_FALSE(std::get<bool>(var_5->function(D_d_0)));
4326 EXPECT_FALSE(std::get<bool>(var_5->function(D_d_1)));
4327 EXPECT_TRUE(std::get<bool>(var_5->function(ggd_0_0_0)));
4328 EXPECT_TRUE(std::get<bool>(var_5->function(ggd_0_0_1)));
4329 EXPECT_FALSE(std::get<bool>(var_5->function(gd_0_0)));
4330 EXPECT_FALSE(std::get<bool>(var_5->function(gd_0_1)));
4331 EXPECT_FALSE(std::get<bool>(var_5->function(d_0)));
4332 EXPECT_FALSE(std::get<bool>(var_5->function(d_1)));
4333 EXPECT_FALSE(std::get<bool>(var_5->function(not_child)));
4334 EXPECT_FALSE(std::get<bool>(var_5->function(not_child_2)));
4335 }
4336
4337
4338
4339
4340
4341 class PIDVariableTest : public ::testing::Test {
4342 protected:
4344 void SetUp() override
4345 {
4349 StoreArray<MCParticle> mcparticles;
4350 StoreArray<PIDLikelihood> likelihood;
4351 StoreArray<Particle> particles;
4352 StoreArray<Track> tracks;
4353 peim.registerInDataStore();
4354 tfrs.registerInDataStore();
4355 mcparticles.registerInDataStore();
4356 likelihood.registerInDataStore();
4357 particles.registerInDataStore();
4358 tracks.registerInDataStore();
4359 particles.registerRelationTo(likelihood);
4360 tracks.registerRelationTo(likelihood);
4362 }
4363
4365 void TearDown() override
4366 {
4368 }
4369 };
4370
4371 TEST_F(PIDVariableTest, LogLikelihood)
4372 {
4373 StoreArray<PIDLikelihood> likelihood;
4374 StoreArray<Particle> particles;
4375 StoreArray<Track> tracks;
4377
4378 // create tracks and trackFitResutls
4379 TRandom3 generator;
4380 const float pValue = 0.5;
4381 const float bField = 1.5;
4382 const int charge = 1;
4383 TMatrixDSym cov6(6);
4384 // Generate a random put orthogonal pair of vectors in the r-phi plane
4385 ROOT::Math::Cartesian2D d(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
4386 ROOT::Math::Cartesian2D pt(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
4387 d.SetXY(d.X(), -(d.X()*pt.X()) / pt.Y());
4388 // Add a random z component
4389 ROOT::Math::XYZVector position(d.X(), d.Y(), generator.Uniform(-1, 1));
4390 ROOT::Math::XYZVector momentum(pt.X(), pt.Y(), generator.Uniform(-1, 1));
4391
4392 auto CDCValue = static_cast<unsigned long long int>(0x300000000000000);
4393 tfrs.appendNew(position, momentum, cov6, charge, Const::electron, pValue, bField, CDCValue, 16777215, 0);
4394 Track mytrack;
4396 Track* allTrack = tracks.appendNew(mytrack);
4397 Track* noSVDTrack = tracks.appendNew(mytrack);
4398 Track* noPIDTrack = tracks.appendNew(mytrack);
4399 Track* dEdxTrack = tracks.appendNew(mytrack);
4400
4401 // Fill by hand likelihood values for all the detectors and hypothesis
4402 // This is clearly not a physical case, since a particle cannot leave good
4403 // signals in both TOP and ARICH
4404 auto* lAll = likelihood.appendNew();
4405 lAll->setLogLikelihood(Const::TOP, Const::electron, 0.18);
4406 lAll->setLogLikelihood(Const::ARICH, Const::electron, 0.16);
4407 lAll->setLogLikelihood(Const::ECL, Const::electron, 0.14);
4408 lAll->setLogLikelihood(Const::CDC, Const::electron, 0.12);
4409 lAll->setLogLikelihood(Const::SVD, Const::electron, 0.1);
4410 lAll->setLogLikelihood(Const::KLM, Const::electron, 0.01);
4411
4412 lAll->setLogLikelihood(Const::TOP, Const::muon, 0.5);
4413 lAll->setLogLikelihood(Const::ARICH, Const::muon, 0.52);
4414 lAll->setLogLikelihood(Const::ECL, Const::muon, 0.54);
4415 lAll->setLogLikelihood(Const::CDC, Const::muon, 0.56);
4416 lAll->setLogLikelihood(Const::SVD, Const::muon, 0.58);
4417 lAll->setLogLikelihood(Const::KLM, Const::muon, 0.8);
4418
4419 lAll->setLogLikelihood(Const::TOP, Const::pion, 0.2);
4420 lAll->setLogLikelihood(Const::ARICH, Const::pion, 0.22);
4421 lAll->setLogLikelihood(Const::ECL, Const::pion, 0.24);
4422 lAll->setLogLikelihood(Const::CDC, Const::pion, 0.26);
4423 lAll->setLogLikelihood(Const::SVD, Const::pion, 0.28);
4424 lAll->setLogLikelihood(Const::KLM, Const::pion, 0.2);
4425
4426 lAll->setLogLikelihood(Const::TOP, Const::kaon, 0.3);
4427 lAll->setLogLikelihood(Const::ARICH, Const::kaon, 0.32);
4428 lAll->setLogLikelihood(Const::ECL, Const::kaon, 0.34);
4429 lAll->setLogLikelihood(Const::CDC, Const::kaon, 0.36);
4430 lAll->setLogLikelihood(Const::SVD, Const::kaon, 0.38);
4431 lAll->setLogLikelihood(Const::KLM, Const::kaon, 0.2);
4432
4433 lAll->setLogLikelihood(Const::TOP, Const::proton, 0.4);
4434 lAll->setLogLikelihood(Const::ARICH, Const::proton, 0.42);
4435 lAll->setLogLikelihood(Const::ECL, Const::proton, 0.44);
4436 lAll->setLogLikelihood(Const::CDC, Const::proton, 0.46);
4437 lAll->setLogLikelihood(Const::SVD, Const::proton, 0.48);
4438 lAll->setLogLikelihood(Const::KLM, Const::proton, 0.02);
4439
4440 lAll->setLogLikelihood(Const::TOP, Const::deuteron, 0.6);
4441 lAll->setLogLikelihood(Const::ARICH, Const::deuteron, 0.62);
4442 lAll->setLogLikelihood(Const::ECL, Const::deuteron, 0.64);
4443 lAll->setLogLikelihood(Const::CDC, Const::deuteron, 0.66);
4444 lAll->setLogLikelihood(Const::SVD, Const::deuteron, 0.68);
4445 lAll->setLogLikelihood(Const::KLM, Const::deuteron, 0.02);
4446
4447 // Likelihoods for all detectors but SVD
4448 auto* lAllNoSVD = likelihood.appendNew();
4449
4450 for (const auto& det : Const::PIDDetectorSet::set()) {
4451 for (const auto& hypo : Const::chargedStableSet) {
4452 if (det != Const::SVD) {
4453 lAllNoSVD->setLogLikelihood(det, hypo, lAll->getLogL(hypo, det));
4454 }
4455 }
4456 }
4457
4458 // Likelihoods for a dEdx only case
4459 auto* ldEdx = likelihood.appendNew();
4460 ldEdx->setLogLikelihood(Const::CDC, Const::electron, 0.12);
4461 ldEdx->setLogLikelihood(Const::SVD, Const::electron, 0.1);
4462
4463 ldEdx->setLogLikelihood(Const::CDC, Const::pion, 0.26);
4464 ldEdx->setLogLikelihood(Const::SVD, Const::pion, 0.28);
4465
4466 ldEdx->setLogLikelihood(Const::CDC, Const::kaon, 0.36);
4467 ldEdx->setLogLikelihood(Const::SVD, Const::kaon, 0.38);
4468
4469 ldEdx->setLogLikelihood(Const::CDC, Const::proton, 0.46);
4470 ldEdx->setLogLikelihood(Const::SVD, Const::proton, 0.48);
4471
4472 ldEdx->setLogLikelihood(Const::CDC, Const::muon, 0.56);
4473 ldEdx->setLogLikelihood(Const::SVD, Const::muon, 0.58);
4474
4475 ldEdx->setLogLikelihood(Const::CDC, Const::deuteron, 0.66);
4476 ldEdx->setLogLikelihood(Const::SVD, Const::deuteron, 0.68);
4477
4478 allTrack->addRelationTo(lAll);
4479 noSVDTrack->addRelationTo(lAllNoSVD);
4480 dEdxTrack->addRelationTo(ldEdx);
4481
4482 // Table with the sum(LogL) for several cases
4483 // All dEdx AllNoSVD
4484 // e 0.71 0.22 0.61
4485 // mu 3.5 1.14 2.92
4486 // pi 1.4 0.54 1.12
4487 // k 1.9 0.74 1.52
4488 // p 2.22 0.94 1.74
4489 // d 3.22 1.34 2.54
4490
4491 auto* particleAll = particles.appendNew(allTrack, Const::pion);
4492 auto* particleNoSVD = particles.appendNew(noSVDTrack, Const::pion);
4493 auto* particledEdx = particles.appendNew(dEdxTrack, Const::pion);
4494 auto* particleNoID = particles.appendNew(noPIDTrack, Const::pion);
4495
4496 double numsumexp = std::exp(0.71) + std::exp(3.5) + std::exp(1.4) + std::exp(1.9) + std::exp(2.22) + std::exp(3.22);
4497 double numsumexp_noSVD = std::exp(0.61) + std::exp(2.92) + std::exp(1.12) + std::exp(1.52) + std::exp(1.74) + std::exp(2.54);
4498
4499 // Basic PID quantities. Currently just wrappers for global probability.
4500 EXPECT_FLOAT_EQ(electronID(particleAll), std::exp(0.71) / numsumexp);
4501 EXPECT_FLOAT_EQ(muonID(particleAll), std::exp(3.5) / numsumexp);
4502 EXPECT_FLOAT_EQ(pionID(particleAll), std::exp(1.4) / numsumexp);
4503 EXPECT_FLOAT_EQ(kaonID(particleAll), std::exp(1.9) / numsumexp);
4504 EXPECT_FLOAT_EQ(protonID(particleAll), std::exp(2.22) / numsumexp);
4505 EXPECT_FLOAT_EQ(deuteronID(particleAll), std::exp(3.22) / numsumexp);
4506
4507 // smart PID that takes the hypothesis into account
4508 auto* particleElectron = particles.appendNew(allTrack, Const::electron);
4509 auto* particleMuon = particles.appendNew(allTrack, Const::muon);
4510 auto* particleKaon = particles.appendNew(allTrack, Const::kaon);
4511 auto* particleProton = particles.appendNew(allTrack, Const::proton);
4512 auto* particleDeuteron = particles.appendNew(allTrack, Const::deuteron);
4513
4514 EXPECT_FLOAT_EQ(particleID(particleAll), std::exp(1.4) / numsumexp); // there's already a pion
4515 EXPECT_FLOAT_EQ(particleID(particleElectron), std::exp(0.71) / numsumexp);
4516 EXPECT_FLOAT_EQ(particleID(particleMuon), std::exp(3.5) / numsumexp);
4517 EXPECT_FLOAT_EQ(particleID(particleKaon), std::exp(1.9) / numsumexp);
4518 EXPECT_FLOAT_EQ(particleID(particleProton), std::exp(2.22) / numsumexp);
4519 EXPECT_FLOAT_EQ(particleID(particleDeuteron), std::exp(3.22) / numsumexp);
4520
4521 // TEMP: PID w/o the SVD.
4522 EXPECT_FLOAT_EQ(electronID_noSVD(particleNoSVD), std::exp(0.61) / numsumexp_noSVD);
4523 EXPECT_FLOAT_EQ(muonID_noSVD(particleNoSVD), std::exp(2.92) / numsumexp_noSVD);
4524 EXPECT_FLOAT_EQ(pionID_noSVD(particleNoSVD), std::exp(1.12) / numsumexp_noSVD);
4525 EXPECT_FLOAT_EQ(kaonID_noSVD(particleNoSVD), std::exp(1.52) / numsumexp_noSVD);
4526 EXPECT_FLOAT_EQ(protonID_noSVD(particleNoSVD), std::exp(1.74) / numsumexp_noSVD);
4527 EXPECT_FLOAT_EQ(deuteronID_noSVD(particleNoSVD), std::exp(2.54) / numsumexp_noSVD);
4528
4529 // Binary PID
4530 std::vector<double> v_pi_K {211., 321.};
4531 std::vector<double> v_pi_p {211., 2212.};
4532 std::vector<double> v_K_p {321., 2212.};
4533 EXPECT_FLOAT_EQ(binaryPID(particleAll, v_pi_K), std::exp(1.4) / (std::exp(1.4) + std::exp(1.9)));
4534 EXPECT_FLOAT_EQ(binaryPID(particleAll, v_pi_p), std::exp(1.4) / (std::exp(1.4) + std::exp(2.22)));
4535 EXPECT_FLOAT_EQ(binaryPID(particleAll, v_K_p), std::exp(1.9) / (std::exp(1.9) + std::exp(2.22)));
4536
4537 // Check what happens if no Likelihood is available
4538 EXPECT_TRUE(std::isnan(electronID(particleNoID)));
4539 EXPECT_TRUE(std::isnan(muonID(particleNoID)));
4540 EXPECT_TRUE(std::isnan(pionID(particleNoID)));
4541 EXPECT_TRUE(std::isnan(kaonID(particleNoID)));
4542 EXPECT_TRUE(std::isnan(protonID(particleNoID)));
4543 EXPECT_TRUE(std::isnan(deuteronID(particleNoID)));
4544
4545 //expert stuff: LogL values
4546 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidLogLikelihoodValueExpert(11, TOP)")->function(particleAll)),
4547 0.18);
4548 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidLogLikelihoodValueExpert(11, ALL)")->function(particleAll)),
4549 0.71);
4550 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidLogLikelihoodValueExpert(2212, TOP, CDC)")->function(
4551 particleAll)), 0.86);
4552
4553 // global probability
4554 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(1000010020, ALL)")->function(particleAll)),
4555 std::exp(3.22) / numsumexp);
4556 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(2212, ALL)")->function(particleAll)),
4557 std::exp(2.22) / numsumexp);
4558 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(211, ALL)")->function(particleAll)),
4559 std::exp(1.4) / numsumexp);
4560 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(321, ALL)")->function(particleAll)),
4561 std::exp(1.9) / numsumexp);
4562 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(13, ALL)")->function(particleAll)),
4563 std::exp(3.5) / numsumexp);
4564 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(11, ALL)")->function(particleAll)),
4565 std::exp(0.71) / numsumexp);
4566 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(211, ALL)")->function(particledEdx)),
4567 std::exp(0.54) / (std::exp(0.22) + std::exp(1.14) + std::exp(0.54) + std::exp(0.74) + std::exp(0.94) + std::exp(1.34)));
4568 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(211, ALL)")->function(particledEdx)),
4569 std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(211, CDC, SVD)")->function(particleAll)));
4570 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(211, CDC)")->function(particledEdx)),
4571 std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(211, CDC)")->function(particleAll)));
4572 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(321, CDC)")->function(particleAll)),
4573 std::exp(0.36) / (std::exp(0.12) + std::exp(0.26) + std::exp(0.36) + std::exp(0.46) + std::exp(0.56) + std::exp(0.66)));
4574
4575 // binary probability
4576 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(321, 2212, ALL)")->function(
4577 particleAll)),
4578 1.0 / (1.0 + std::exp(2.22 - 1.9)));
4579 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(321, 2212, ALL)")->function(
4580 particledEdx)),
4581 1.0 / (1.0 + std::exp(0.94 - 0.74)));
4582 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(321, 2212, CDC, SVD)")->function(
4583 particleAll)),
4584 1.0 / (1.0 + std::exp(0.94 - 0.74)));
4585
4586 // No likelihood available
4587 EXPECT_TRUE(std::isnan(std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(321, 2212, KLM)")->function(
4588 particledEdx))));
4589 EXPECT_TRUE(std::isnan(std::get<double>(Manager::Instance().getVariable("pidLogLikelihoodValueExpert(11, TOP, CDC, SVD)")->function(
4590 particleNoID))));
4591 EXPECT_TRUE(std::isnan(std::get<double>(Manager::Instance().getVariable("pidLogLikelihoodValueExpert(11, TOP)")->function(
4592 particledEdx))));
4593 EXPECT_TRUE(std::isnan(std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(321, 2212, KLM)")->function(
4594 particledEdx))));
4595 EXPECT_TRUE(std::isnan(std::get<double>
4596 (Manager::Instance().getVariable("pidPairProbabilityExpert(321, 2212, ECL, TOP, ARICH)")->function(
4597 particledEdx))));
4598 EXPECT_FALSE(std::isnan(std::get<double>
4599 (Manager::Instance().getVariable("pidPairProbabilityExpert(321, 2212, ECL, TOP, ARICH, SVD)")->function(
4600 particledEdx))));
4601 //Mostlikely PDG tests:
4602 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidMostLikelyPDG()")->function(particledEdx)), 1.00001e+09);
4603 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidMostLikelyPDG(0.5, 0.1, 0.1, 0.1, 0.1, 0.1)")->function(
4604 particledEdx)),
4605 Const::electron.getPDGCode());
4606 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidMostLikelyPDG(0.1, 0.5, 0.1, 0.1, 0.1, 0.1)")->function(
4607 particledEdx)),
4608 Const::muon.getPDGCode());
4609 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidMostLikelyPDG(0.1, 0.1, 0.5, 0.1, 0.1, 0.1)")->function(
4610 particledEdx)),
4611 Const::pion.getPDGCode());
4612 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidMostLikelyPDG(0.1, 0.1, 0.1, 0.5, 0.1, 0.1)")->function(
4613 particledEdx)),
4614 Const::kaon.getPDGCode());
4615 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidMostLikelyPDG(0.1, 0.1, 0.1, 0.1, 0.5, 0.1)")->function(
4616 particledEdx)),
4617 Const::proton.getPDGCode());
4618 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidMostLikelyPDG(0, 1., 0, 0, 0, 0)")->function(particledEdx)),
4619 Const::muon.getPDGCode());
4620 }
4621
4622 TEST_F(PIDVariableTest, MissingLikelihood)
4623 {
4624 StoreArray<PIDLikelihood> likelihood;
4625 StoreArray<Particle> particles;
4626 StoreArray<Track> tracks;
4628
4629 // create tracks and trackFitResutls
4630 TRandom3 generator;
4631 const float pValue = 0.5;
4632 const float bField = 1.5;
4633 const int charge = 1;
4634 TMatrixDSym cov6(6);
4635 // Generate a random put orthogonal pair of vectors in the r-phi plane
4636 ROOT::Math::Cartesian2D d(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
4637 ROOT::Math::Cartesian2D pt(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
4638 d.SetXY(d.X(), -(d.X()*pt.X()) / pt.Y());
4639 // Add a random z component
4640 ROOT::Math::XYZVector position(d.X(), d.Y(), generator.Uniform(-1, 1));
4641 ROOT::Math::XYZVector momentum(pt.X(), pt.Y(), generator.Uniform(-1, 1));
4642
4643 auto CDCValue = static_cast<unsigned long long int>(0x300000000000000);
4644 tfrs.appendNew(position, momentum, cov6, charge, Const::electron, pValue, bField, CDCValue, 16777215, 0);
4645 Track mytrack;
4647 Track* savedTrack1 = tracks.appendNew(mytrack);
4648 Track* savedTrack2 = tracks.appendNew(mytrack);
4649 Track* savedTrack3 = tracks.appendNew(mytrack);
4650 Track* savedTrack4 = tracks.appendNew(mytrack);
4651
4652 auto* l1 = likelihood.appendNew();
4653 l1->setLogLikelihood(Const::TOP, Const::electron, 0.18);
4654 l1->setLogLikelihood(Const::ECL, Const::electron, 0.14);
4655 savedTrack1->addRelationTo(l1);
4656
4657 auto* electron = particles.appendNew(savedTrack1, Const::electron);
4658
4659 auto* l2 = likelihood.appendNew();
4660 l2->setLogLikelihood(Const::TOP, Const::pion, 0.2);
4661 l2->setLogLikelihood(Const::ARICH, Const::pion, 0.22);
4662 l2->setLogLikelihood(Const::ECL, Const::pion, 0.24);
4663 l2->setLogLikelihood(Const::CDC, Const::pion, 0.26);
4664 l2->setLogLikelihood(Const::SVD, Const::pion, 0.28);
4665 savedTrack2->addRelationTo(l2);
4666
4667 auto* pion = particles.appendNew(savedTrack2, Const::pion);
4668
4669 auto* l3 = likelihood.appendNew();
4670 l3->setLogLikelihood(Const::TOP, Const::kaon, 0.3);
4671 l3->setLogLikelihood(Const::ARICH, Const::kaon, 0.32);
4672 savedTrack3->addRelationTo(l3);
4673
4674 auto* kaon = particles.appendNew(savedTrack3, Const::kaon);
4675
4676 auto* l4 = likelihood.appendNew();
4677 l4->setLogLikelihood(Const::ARICH, Const::proton, 0.42);
4678 l4->setLogLikelihood(Const::ECL, Const::proton, 0.44);
4679 l4->setLogLikelihood(Const::CDC, Const::proton, 0.46);
4680 l4->setLogLikelihood(Const::SVD, Const::proton, 0.48);
4681 savedTrack4->addRelationTo(l4);
4682
4683 auto* proton = particles.appendNew(savedTrack4, Const::proton);
4684
4685 const Manager::Var* varMissECL = Manager::Instance().getVariable("pidMissingProbabilityExpert(ECL)");
4686 const Manager::Var* varMissTOP = Manager::Instance().getVariable("pidMissingProbabilityExpert(TOP)");
4687 const Manager::Var* varMissARICH = Manager::Instance().getVariable("pidMissingProbabilityExpert(ARICH)");
4688
4689
4690 EXPECT_FLOAT_EQ(std::get<double>(varMissTOP->function(electron)), 0.0);
4691 EXPECT_FLOAT_EQ(std::get<double>(varMissTOP->function(pion)), 0.0);
4692 EXPECT_FLOAT_EQ(std::get<double>(varMissTOP->function(kaon)), 0.0);
4693 EXPECT_FLOAT_EQ(std::get<double>(varMissTOP->function(proton)), 1.0);
4694
4695 EXPECT_FLOAT_EQ(std::get<double>(varMissARICH->function(electron)), 1.0);
4696 EXPECT_FLOAT_EQ(std::get<double>(varMissARICH->function(pion)), 0.0);
4697 EXPECT_FLOAT_EQ(std::get<double>(varMissARICH->function(kaon)), 0.0);
4698 EXPECT_FLOAT_EQ(std::get<double>(varMissARICH->function(proton)), 0.0);
4699
4700 EXPECT_FLOAT_EQ(std::get<double>(varMissECL->function(electron)), 0.0);
4701 EXPECT_FLOAT_EQ(std::get<double>(varMissECL->function(pion)), 0.0);
4702 EXPECT_FLOAT_EQ(std::get<double>(varMissECL->function(kaon)), 1.0);
4703 EXPECT_FLOAT_EQ(std::get<double>(varMissECL->function(proton)), 0.0);
4704 }
4705
4706 class FlightInfoTest : public ::testing::Test {
4707 protected:
4709 void SetUp() override
4710 {
4714 StoreArray<MCParticle> mcParticles;
4715 StoreArray<Particle> particles;
4716 particles.registerRelationTo(mcParticles);
4719
4720
4721 // Insert MC particle logic here
4722 MCParticle mcKs;
4723 mcKs.setPDG(Const::Kshort.getPDGCode());
4724 mcKs.setProductionVertex(1.0, 1.0, 0.0);
4725 mcKs.setDecayVertex(4.0, 5.0, 0.0);
4726 mcKs.setProductionTime(0);
4727 mcKs.setMassFromPDG();
4728 mcKs.setMomentum(1.164, 1.55200, 0);
4729 float decayTime = 5 * mcKs.getMass() / mcKs.getEnergy();
4730 mcKs.setDecayTime(decayTime);
4732 MCParticle* newMCKs = mcParticles.appendNew(mcKs);
4733
4734
4735
4736 MCParticle mcDp;
4737 mcDp.setPDG(411);
4738 mcDp.setDecayVertex(1.0, 1.0, 0.0);
4739 mcDp.setMassFromPDG();
4741 MCParticle* newMCDp = mcParticles.appendNew(mcDp);
4742
4743 // Insert Reco particle logic here
4744 PxPyPzEVector momentum;
4745 TMatrixFSym error(7);
4746 error.Zero();
4747 error(0, 0) = 0.05;
4748 error(1, 1) = 0.2;
4749 error(2, 2) = 0.4;
4750 error(3, 3) = 0.01;
4751 error(4, 4) = 0.04;
4752 error(5, 5) = 0.00875;
4753 error(6, 6) = 0.01;
4754 Particle pi(PxPyPzEVector(1.59607, 1.19705, 0, 2), 211);
4755 momentum += pi.get4Vector();
4756 Particle* newpi = particles.appendNew(pi);
4757
4758
4759 Particle Ks(PxPyPzEVector(1.164, 1.55200, 0, 2), 310, Particle::c_Unflavored, Particle::c_Composite, 0);
4760 Ks.setVertex(XYZVector(4.0, 5.0, 0.0));
4761 Ks.setMomentumVertexErrorMatrix(error); // (order: px,py,pz,E,x,y,z)
4762 momentum += Ks.get4Vector();
4763 Ks.addExtraInfo("prodVertX", 1.0);
4764 Ks.addExtraInfo("prodVertY", 1.0);
4765 Ks.addExtraInfo("prodVertZ", 0.0);
4766 Ks.addExtraInfo("prodVertSxx", 0.04);
4767 Ks.addExtraInfo("prodVertSxy", 0.0);
4768 Ks.addExtraInfo("prodVertSxz", 0.0);
4769 Ks.addExtraInfo("prodVertSyx", 0.0);
4770 Ks.addExtraInfo("prodVertSyy", 0.00875);
4771 Ks.addExtraInfo("prodVertSyz", 0.0);
4772 Ks.addExtraInfo("prodVertSzx", 0.0);
4773 Ks.addExtraInfo("prodVertSzy", 0.0);
4774 Ks.addExtraInfo("prodVertSzz", 0.01);
4775 Particle* newKs = particles.appendNew(Ks);
4776 newKs->addRelationTo(newMCKs);
4777
4778
4779 Particle Dp(momentum, 411, Particle::c_Flavored, Particle::c_Composite, 0);
4780 Dp.appendDaughter(newpi);
4781 Dp.appendDaughter(newKs);
4782 XYZVector motherVtx(1.0, 1.0, 0.0);
4783 Dp.setVertex(motherVtx);
4784 Dp.setMomentumVertexErrorMatrix(error); // (order: px,py,pz,E,x,y,z)
4785 Dp.addExtraInfo("prodVertX", 0.0);
4786 Dp.addExtraInfo("prodVertY", 1.0);
4787 Dp.addExtraInfo("prodVertZ", -2.0);
4788 Dp.addExtraInfo("prodVertSxx", 0.04);
4789 Dp.addExtraInfo("prodVertSxy", 0.0);
4790 Dp.addExtraInfo("prodVertSxz", 0.0);
4791 Dp.addExtraInfo("prodVertSyx", 0.0);
4792 Dp.addExtraInfo("prodVertSyy", 0.01);
4793 Dp.addExtraInfo("prodVertSyz", 0.0);
4794 Dp.addExtraInfo("prodVertSzx", 0.0);
4795 Dp.addExtraInfo("prodVertSzy", 0.0);
4796 Dp.addExtraInfo("prodVertSzz", 0.1575);
4797 Particle* newDp = particles.appendNew(Dp);
4798 newDp->addRelationTo(newMCDp);
4799
4800 }
4801
4803 void TearDown() override
4804 {
4806 }
4807 };
4808 TEST_F(FlightInfoTest, flightDistance)
4809 {
4810 StoreArray<Particle> particles{};
4811 const Particle* newKs = particles[1]; // Ks had flight distance of 5 cm
4812
4813 const Manager::Var* var = Manager::Instance().getVariable("flightDistance");
4814 ASSERT_NE(var, nullptr);
4815 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 5.0);
4816 }
4817 TEST_F(FlightInfoTest, flightDistanceErr)
4818 {
4819 StoreArray<Particle> particles{};
4820 const Particle* newKs = particles[1]; // Ks had flight distance of 5 cm
4821
4822 const Manager::Var* var = Manager::Instance().getVariable("flightDistanceErr");
4823 ASSERT_NE(var, nullptr);
4824 EXPECT_GT(std::get<double>(var->function(newKs)), 0.0);
4825 }
4826 TEST_F(FlightInfoTest, flightTime)
4827 {
4828 StoreArray<Particle> particles{};
4829 const Particle* newKs = particles[1]; // Ks had flight time of 0.0427 us (t = d/c * m/p)
4830
4831 const Manager::Var* var = Manager::Instance().getVariable("flightTime");
4832 ASSERT_NE(var, nullptr);
4833 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 5.0 / Const::speedOfLight * newKs->getPDGMass() / newKs->getP());
4834 }
4835
4836 TEST_F(FlightInfoTest, flightTimeErr)
4837 {
4838 StoreArray<Particle> particles{};
4839 const Particle* newKs = particles[1]; // Ks should have positive flight distance uncertainty
4840
4841 const Manager::Var* var = Manager::Instance().getVariable("flightTimeErr");
4842 ASSERT_NE(var, nullptr);
4843 EXPECT_GT(std::get<double>(var->function(newKs)), 0.0);
4844 }
4845
4846 TEST_F(FlightInfoTest, flightDistanceOfDaughter)
4847 {
4848 StoreArray<Particle> particles{};
4849 const Particle* newDp = particles[2]; // Get D+, its daughter Ks had flight distance of 5 cm
4850
4851 const Manager::Var* var = Manager::Instance().getVariable("flightDistanceOfDaughter(1)");
4852 ASSERT_NE(var, nullptr);
4853 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 5.0);
4854
4855 var = Manager::Instance().getVariable("flightDistanceOfDaughter(3)");
4856 ASSERT_NE(var, nullptr);
4857 EXPECT_TRUE(std::isnan(std::get<double>(var->function(newDp))));
4858 }
4859 TEST_F(FlightInfoTest, flightDistanceOfDaughterErr)
4860 {
4861 StoreArray<Particle> particles{};
4862 const Particle* newDp = particles[2]; // Get D+, its daughter Ks should have positive flight distance uncertainty
4863
4864 const Manager::Var* var = Manager::Instance().getVariable("flightDistanceOfDaughterErr(1)");
4865 ASSERT_NE(var, nullptr);
4866 EXPECT_GT(std::get<double>(var->function(newDp)), 0.0);
4867
4868 var = Manager::Instance().getVariable("flightDistanceOfDaughterErr(3)");
4869 ASSERT_NE(var, nullptr);
4870 EXPECT_TRUE(std::isnan(std::get<double>(var->function(newDp))));
4871 }
4872 TEST_F(FlightInfoTest, flightTimeOfDaughter)
4873 {
4874 StoreArray<Particle> particles{};
4875 const Particle* newDp = particles[2]; // Get D+, its daughter Ks had flight time of 0.0427 us (t = d/c * m/p)
4876
4877 const Manager::Var* var = Manager::Instance().getVariable("flightTimeOfDaughter(1)");
4878 ASSERT_NE(var, nullptr);
4879 const Particle* Ks = newDp->getDaughter(1);
4880
4881 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 5.0 / Const::speedOfLight * Ks->getPDGMass() / Ks->getP());
4882
4883 var = Manager::Instance().getVariable("flightTimeOfDaughter(3)");
4884 ASSERT_NE(var, nullptr);
4885 EXPECT_TRUE(std::isnan(std::get<double>(var->function(newDp))));
4886 }
4887 TEST_F(FlightInfoTest, flightTimeOfDaughterErr)
4888 {
4889 StoreArray<Particle> particles{};
4890 const Particle* newDp = particles[2]; // Get D+, its daughter Ks should have positive flight time uncertainty
4891
4892 const Manager::Var* var = Manager::Instance().getVariable("flightTimeOfDaughterErr(1)");
4893 ASSERT_NE(var, nullptr);
4894 EXPECT_GT(std::get<double>(var->function(newDp)), 0.0);
4895
4896 var = Manager::Instance().getVariable("flightTimeOfDaughterErr(3)");
4897 ASSERT_NE(var, nullptr);
4898 EXPECT_TRUE(std::isnan(std::get<double>(var->function(newDp))));
4899 }
4900 TEST_F(FlightInfoTest, mcFlightDistanceOfDaughter)
4901 {
4902 StoreArray<Particle> particles{};
4903 const Particle* newDp = particles[2]; // Get D+, its daughter Ks had flight distance of 5 cm
4904
4905 const Manager::Var* var = Manager::Instance().getVariable("mcFlightDistanceOfDaughter(1)");
4906 ASSERT_NE(var, nullptr);
4907
4908 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 5.0);
4909
4910 var = Manager::Instance().getVariable("mcFlightDistanceOfDaughter(3)");
4911 ASSERT_NE(var, nullptr);
4912 EXPECT_TRUE(std::isnan(std::get<double>(var->function(newDp))));
4913 }
4914 TEST_F(FlightInfoTest, mcFlightTimeOfDaughter)
4915 {
4916 StoreArray<Particle> particles{};
4917 const Particle* newDp = particles[2]; // Get D+, its daughter Ks had flight time of 0.0427 us (t = d/c * m/p)
4918
4919 const Manager::Var* var = Manager::Instance().getVariable("mcFlightTimeOfDaughter(1)");
4920 ASSERT_NE(var, nullptr);
4921 auto* Ks = newDp->getDaughter(1)->getRelatedTo<MCParticle>();
4922 // double p = Ks->getMomentum().Mag();
4923 // EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 5.0 / Const::speedOfLight * Ks->getMass() / p);
4924
4925 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), Ks->getLifetime() / Ks->getEnergy()*Ks->getMass());
4926
4927 var = Manager::Instance().getVariable("mcFlightTimeOfDaughter(3)");
4928 ASSERT_NE(var, nullptr);
4929 EXPECT_TRUE(std::isnan(std::get<double>(var->function(newDp))));
4930 }
4931
4932 TEST_F(FlightInfoTest, vertexDistance)
4933 {
4934 StoreArray<Particle> particles{};
4935 const Particle* newKS = particles[1]; // Get KS, as it has both a production and decay vertex
4936
4937 const Manager::Var* var = Manager::Instance().getVariable("vertexDistance");
4938 ASSERT_NE(var, nullptr);
4939 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKS)), 5.0);
4940 }
4941
4942 TEST_F(FlightInfoTest, vertexDistanceError)
4943 {
4944 StoreArray<Particle> particles{};
4945 const Particle* newKS = particles[1]; // Get KS, as it has both a production and decay vertex
4946
4947 const Manager::Var* var = Manager::Instance().getVariable("vertexDistanceErr");
4948 ASSERT_NE(var, nullptr);
4949 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKS)), 0.2);
4950 }
4951
4952 TEST_F(FlightInfoTest, vertexDistanceSignificance)
4953 {
4954 StoreArray<Particle> particles{};
4955 const Particle* newKS = particles[1]; // Get KS, as it has both a production and decay vertex
4956
4957 const Manager::Var* var = Manager::Instance().getVariable("vertexDistanceSignificance");
4958 ASSERT_NE(var, nullptr);
4959 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKS)), 25);
4960 }
4961
4962 TEST_F(FlightInfoTest, vertexDistanceOfDaughter)
4963 {
4964 StoreArray<Particle> particles{};
4965 const Particle* newDp = particles[2]; // Get D+, its daughter KS has both a production and decay vertex
4966
4967 const Manager::Var* var = Manager::Instance().getVariable("vertexDistanceOfDaughter(1, 0)");
4968 ASSERT_NE(var, nullptr);
4969 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 5.0);
4970
4971 var = Manager::Instance().getVariable("vertexDistanceOfDaughter(1)");
4972 ASSERT_NE(var, nullptr);
4973 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 6.0);
4974
4975 var = Manager::Instance().getVariable("vertexDistanceOfDaughter(2)");
4976 ASSERT_NE(var, nullptr);
4977 EXPECT_TRUE(std::isnan(std::get<double>(var->function(newDp))));
4978 }
4979
4980 TEST_F(FlightInfoTest, vertexDistanceOfDaughterError)
4981 {
4982 StoreArray<Particle> particles{};
4983 const Particle* newDp = particles[2]; // Get D+, its daughter KS has both a production and decay vertex
4984
4985 const Manager::Var* var = Manager::Instance().getVariable("vertexDistanceOfDaughterErr(1, 0)");
4986 ASSERT_NE(var, nullptr);
4987 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 0.2);
4988
4989 var = Manager::Instance().getVariable("vertexDistanceOfDaughterErr(1)");
4990 ASSERT_NE(var, nullptr);
4991 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 0.25);
4992 }
4993
4994 TEST_F(FlightInfoTest, vertexDistanceOfDaughterSignificance)
4995 {
4996 StoreArray<Particle> particles{};
4997 const Particle* newDp = particles[2]; // Get D+, its daughter KS has both a production and decay vertex
4998
4999 const Manager::Var* var = Manager::Instance().getVariable("vertexDistanceOfDaughterSignificance(1, 0)");
5000 ASSERT_NE(var, nullptr);
5001 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 25);
5002
5003 var = Manager::Instance().getVariable("vertexDistanceOfDaughterSignificance(1)");
5004 ASSERT_NE(var, nullptr);
5005 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 24);
5006 }
5007
5008 class VertexVariablesTest : public ::testing::Test {
5009 protected:
5011 void SetUp() override
5012 {
5016 StoreArray<MCParticle> mcParticles;
5017 StoreArray<Particle> particles;
5018 particles.registerRelationTo(mcParticles);
5021
5022
5023 // Insert MC particle logic here
5024 MCParticle mcKs;
5025 mcKs.setPDG(Const::Kshort.getPDGCode());
5026 mcKs.setDecayVertex(4.0, 5.0, 0.0);
5027 mcKs.setProductionVertex(1.0, 2.0, 3.0);
5028 mcKs.setMassFromPDG();
5029 mcKs.setMomentum(1.164, 1.55200, 0);
5031 MCParticle* newMCKs = mcParticles.appendNew(mcKs);
5032
5033 Particle Ks(PxPyPzEVector(1.164, 1.55200, 0, 2), 310);
5034 Ks.setVertex(XYZVector(4.0, 5.0, 0.0));
5035 Ks.addExtraInfo("prodVertX", 1.0);
5036 Ks.addExtraInfo("prodVertY", 2.0);
5037 Ks.addExtraInfo("prodVertZ", 3.0);
5038 Ks.addExtraInfo("prodVertSxx", 0.1);
5039 Ks.addExtraInfo("prodVertSxy", 0.2);
5040 Ks.addExtraInfo("prodVertSxz", 0.3);
5041 Ks.addExtraInfo("prodVertSyx", 0.4);
5042 Ks.addExtraInfo("prodVertSyy", 0.5);
5043 Ks.addExtraInfo("prodVertSyz", 0.6);
5044 Ks.addExtraInfo("prodVertSzx", 0.7);
5045 Ks.addExtraInfo("prodVertSzy", 0.8);
5046 Ks.addExtraInfo("prodVertSzz", 0.9);
5047 Particle* newKs = particles.appendNew(Ks);
5048 newKs->addRelationTo(newMCKs);
5049 }
5050
5052 void TearDown() override
5053 {
5055 }
5056 };
5057
5058 // MC vertex tests
5059 TEST_F(VertexVariablesTest, mcDecayVertexX)
5060 {
5061 StoreArray<Particle> particles{};
5062 const Particle* newKs = particles[0]; // Ks had truth decay x is 4.0
5063
5064 const Manager::Var* var = Manager::Instance().getVariable("mcDecayVertexX");
5065 ASSERT_NE(var, nullptr);
5066 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 4.0);
5067 }
5068
5069 TEST_F(VertexVariablesTest, mcDecayVertexY)
5070 {
5071 StoreArray<Particle> particles{};
5072 const Particle* newKs = particles[0]; // Ks had truth decay y is 5.0
5073
5074 const Manager::Var* var = Manager::Instance().getVariable("mcDecayVertexY");
5075 ASSERT_NE(var, nullptr);
5076 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 5.0);
5077 }
5078
5079 TEST_F(VertexVariablesTest, mcDecayVertexZ)
5080 {
5081 StoreArray<Particle> particles{};
5082 const Particle* newKs = particles[0]; // Ks had truth decay z is 0.0
5083
5084 const Manager::Var* var = Manager::Instance().getVariable("mcDecayVertexZ");
5085 ASSERT_NE(var, nullptr);
5086 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.0);
5087 }
5088
5089
5090 TEST_F(VertexVariablesTest, mcDecayVertexFromIPDistance)
5091 {
5092 StoreArray<Particle> particles{};
5093 const Particle* newKs = particles[0]; // Ks had truth distance of sqrt(41)
5094
5095 const Manager::Var* var = Manager::Instance().getVariable("mcDecayVertexFromIPDistance");
5096 ASSERT_NE(var, nullptr);
5097 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), sqrt(4.0 * 4.0 + 5.0 * 5.0));
5098 }
5099
5100 TEST_F(VertexVariablesTest, mcDecayVertexRho)
5101 {
5102 StoreArray<Particle> particles{};
5103 const Particle* newKs = particles[0]; // Ks had truth rho of sqrt(41)
5104
5105 const Manager::Var* var = Manager::Instance().getVariable("mcDecayVertexRho");
5106 ASSERT_NE(var, nullptr);
5107 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), sqrt(4.0 * 4.0 + 5.0 * 5.0));
5108 }
5109
5110 TEST_F(VertexVariablesTest, mcProductionVertexX)
5111 {
5112 StoreArray<Particle> particles{};
5113 const Particle* newKs = particles[0]; // Ks had production vertex x of 1.0 cm
5114
5115 const Manager::Var* var = Manager::Instance().getVariable("mcProductionVertexX");
5116 ASSERT_NE(var, nullptr);
5117 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 1.0);
5118 }
5119
5120 TEST_F(VertexVariablesTest, mcProductionVertexY)
5121 {
5122 StoreArray<Particle> particles{};
5123 const Particle* newKs = particles[0]; // Ks had production vertex y of 2.0 cm
5124
5125 const Manager::Var* var = Manager::Instance().getVariable("mcProductionVertexY");
5126 ASSERT_NE(var, nullptr);
5127 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 2.0);
5128 }
5129
5130 TEST_F(VertexVariablesTest, mcProductionVertexZ)
5131 {
5132 StoreArray<Particle> particles{};
5133 const Particle* newKs = particles[0]; // Ks had production vertex z of 3.0 cm
5134
5135 const Manager::Var* var = Manager::Instance().getVariable("mcProductionVertexZ");
5136 ASSERT_NE(var, nullptr);
5137 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 3.0);
5138 }
5139
5140 // Production position tests
5141
5142 TEST_F(VertexVariablesTest, prodVertexX)
5143 {
5144 StoreArray<Particle> particles{};
5145 const Particle* newKs = particles[0]; // Ks had production vertex x of 1.0 cm
5146
5147 const Manager::Var* var = Manager::Instance().getVariable("prodVertexX");
5148 ASSERT_NE(var, nullptr);
5149 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 1.0);
5150 }
5151 TEST_F(VertexVariablesTest, prodVertexY)
5152 {
5153 StoreArray<Particle> particles{};
5154 const Particle* newKs = particles[0]; // Ks had production vertex y of 2.0 cm
5155
5156 const Manager::Var* var = Manager::Instance().getVariable("prodVertexY");
5157 ASSERT_NE(var, nullptr);
5158 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 2.0);
5159 }
5160 TEST_F(VertexVariablesTest, prodVertexZ)
5161 {
5162 StoreArray<Particle> particles{};
5163 const Particle* newKs = particles[0]; // Ks had production vertex z of 3.0 cm
5164
5165 const Manager::Var* var = Manager::Instance().getVariable("prodVertexZ");
5166 ASSERT_NE(var, nullptr);
5167 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 3.0);
5168 }
5169
5170 // Production Covariance tests
5171
5172 TEST_F(VertexVariablesTest, prodVertexCov)
5173 {
5174 StoreArray<Particle> particles{};
5175 const Particle* newKs = particles[0]; // Ks had production vertex covariance xx of .1 cm
5176
5177 //const Manager::Var* var = Manager::Instance().getVariable("prodVertexCovXX");
5178 const Manager::Var* var = Manager::Instance().getVariable("prodVertexCov(0,0)");
5179 ASSERT_NE(var, nullptr);
5180 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.1);
5181 var = Manager::Instance().getVariable("prodVertexCov(0,1)");
5182 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.2);
5183 var = Manager::Instance().getVariable("prodVertexCov(0,2)");
5184 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.3);
5185 var = Manager::Instance().getVariable("prodVertexCov(1,0)");
5186 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.4);
5187 var = Manager::Instance().getVariable("prodVertexCov(1,1)");
5188 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.5);
5189 var = Manager::Instance().getVariable("prodVertexCov(1,2)");
5190 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.6);
5191 var = Manager::Instance().getVariable("prodVertexCov(2,0)");
5192 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.7);
5193 var = Manager::Instance().getVariable("prodVertexCov(2,1)");
5194 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.8);
5195 var = Manager::Instance().getVariable("prodVertexCov(2,2)");
5196 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.9);
5197 var = Manager::Instance().getVariable("prodVertexXErr");
5198 ASSERT_NE(var, nullptr);
5199 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), sqrt(0.1));
5200 var = Manager::Instance().getVariable("prodVertexYErr");
5201 ASSERT_NE(var, nullptr);
5202 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), sqrt(0.5));
5203 var = Manager::Instance().getVariable("prodVertexZErr");
5204 ASSERT_NE(var, nullptr);
5205 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), sqrt(0.9));
5206 }
5207
5208 // Tests of ContinuumSuppressionVariables
5209
5210 TEST_F(MetaVariableTest, KSFWVariables)
5211 {
5212 // simple tests that do not require the ROE builder nor the CS builder
5213
5214 // check that garbage input throws helpful B2FATAL
5215 EXPECT_B2FATAL(Manager::Instance().getVariable("KSFWVariables(NONSENSE)"));
5216
5217 // check for NaN if we don't have a CS object for this particle
5218 StoreArray<Particle> myParticles;
5219 const Particle* particle_with_no_cs = myParticles.appendNew();
5220 const Manager::Var* var = Manager::Instance().getVariable("KSFWVariables(mm2)");
5221 EXPECT_TRUE(std::isnan(std::get<double>(var->function(particle_with_no_cs))));
5222
5223 // check that FS1 set as third argument, throws a B2ERROR
5224 EXPECT_B2ERROR(Manager::Instance().getVariable("KSFWVariables(et, mask, FS1)"));
5225 }
5226
5227 TEST_F(MetaVariableTest, CleoConeCS)
5228 {
5229 // simple tests that do not require the ROE builder nor the CS builder
5230
5231 // check that garbage input throws helpful B2FATAL
5232 EXPECT_B2FATAL(Manager::Instance().getVariable("CleoConeCS(NONSENSE)"));
5233
5234 // check for NaN if we don't have a CS object for this particle
5235 StoreArray<Particle> myParticles;
5236 const Particle* particle_with_no_cs = myParticles.appendNew();
5237 const Manager::Var* var = Manager::Instance().getVariable("CleoConeCS(0)");
5238 EXPECT_TRUE(std::isnan(std::get<double>(var->function(particle_with_no_cs))));
5239
5240 // check that string other than ROE as second argument, which is interpreted as mask name, returns NaN
5241 var = Manager::Instance().getVariable("CleoConeCS(0, NOTROE)");
5242 EXPECT_TRUE(std::isnan(std::get<double>(var->function(particle_with_no_cs))));
5243
5244 // check that ROE set as third argument, throws a B2ERROR
5245 EXPECT_B2ERROR(Manager::Instance().getVariable("CleoConeCS(0, mask, ROE)"));
5246 }
5247
5248 TEST_F(MetaVariableTest, TransformedNetworkOutput)
5249 {
5250 // check that garbage input throws helpful B2FATAL
5251 EXPECT_B2FATAL(Manager::Instance().getVariable("transformedNetworkOutput(NONSENSE)"));
5252
5253 // check that helpful B2FATAL is thrown if second or third argument is not a double
5254 EXPECT_B2FATAL(Manager::Instance().getVariable("transformedNetworkOutput(NONEXISTENT, 0, NOTDOUBLE)"));
5255 EXPECT_B2FATAL(Manager::Instance().getVariable("transformedNetworkOutput(NONEXISTENT, NOTDOUBLE, 1)"));
5256
5257 // check for NaN if network output variable does not exist (no matter whether particle is provided or not)
5258 StoreArray<Particle> myParticles;
5259 const Particle* particle = myParticles.appendNew();
5260 const Manager::Var* var = Manager::Instance().getVariable("transformedNetworkOutput(NONEXISTENT, 0, 1)");
5261 EXPECT_TRUE(std::isnan(std::get<double>(var->function(particle))));
5262 StoreObjPtr<EventExtraInfo> eventExtraInfo;
5263 if (not eventExtraInfo.isValid())
5264 eventExtraInfo.create();
5265 var = Manager::Instance().getVariable("transformedNetworkOutput(NONEXISTENT, 0, 1)");
5266 EXPECT_TRUE(std::isnan(std::get<double>(var->function(nullptr))));
5267 }
5268}
Provides a type-safe way to pass members of the chargedStableSet set.
Definition: Const.h:589
int getPDGCode() const
PDG code.
Definition: Const.h:473
static DetectorSet set()
Accessor for the set of valid detector IDs.
Definition: Const.h:333
static const ChargedStable muon
muon particle
Definition: Const.h:660
static const ParticleSet chargedStableSet
set of charged stable particles
Definition: Const.h:618
static const ChargedStable pion
charged pion particle
Definition: Const.h:661
static const ParticleType Klong
K^0_L particle.
Definition: Const.h:678
static const double speedOfLight
[cm/ns]
Definition: Const.h:695
static const ChargedStable proton
proton particle
Definition: Const.h:663
static const ParticleType Kshort
K^0_S particle.
Definition: Const.h:677
static const ChargedStable kaon
charged kaon particle
Definition: Const.h:662
static const ParticleType photon
photon particle
Definition: Const.h:673
static const ChargedStable electron
electron particle
Definition: Const.h:659
static const ChargedStable deuteron
deuteron particle
Definition: Const.h:664
EStoreFlags
Flags describing behaviours of objects etc.
Definition: DataStore.h:69
@ c_DontWriteOut
Object/array should be NOT saved by output modules.
Definition: DataStore.h:71
static DataStore & Instance()
Instance of singleton Store.
Definition: DataStore.cc:53
void setInitializeActive(bool active)
Setter for m_initializeActive.
Definition: DataStore.cc:93
void reset(EDurability durability)
Frees memory occupied by data store items and removes all objects from the map.
Definition: DataStore.cc:85
ECL cluster data.
Definition: ECLCluster.h:27
void setTheta(double theta)
Set Theta of Shower (radian).
Definition: ECLCluster.h:217
void setPhi(double phi)
Set Phi of Shower (radian).
Definition: ECLCluster.h:220
void setClusterId(int clusterid)
Set cluster id.
Definition: ECLCluster.h:145
void setHypothesis(EHypothesisBit hypothesis)
Set hypotheses.
Definition: ECLCluster.h:123
void setEnergy(double energy)
Set Corrected Energy (GeV).
Definition: ECLCluster.h:226
void setR(double r)
Set R (in cm).
Definition: ECLCluster.h:223
Singleton class responsible for loading detector parameters from an XML file.
Definition: Gearbox.h:34
Class to represent Particle data in graph.
void comesFrom(GraphParticle &mother)
Tells the graph that this particle is a decay product of mother.
Class to build, validate and sort a particle decay chain.
void generateList(const std::string &name="", int options=c_setNothing)
Generates the MCParticle list and stores it in the StoreArray with the given name.
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
float getEnergy() const
Return particle energy in GeV.
Definition: MCParticle.h:136
@ c_PrimaryParticle
bit 0: Particle is primary particle.
Definition: MCParticle.h:47
void setDecayTime(float time)
Set decay time.
Definition: MCParticle.h:379
void setMass(float mass)
Set particle mass.
Definition: MCParticle.h:355
void setDecayVertex(const ROOT::Math::XYZVector &vertex)
Set decay vertex.
Definition: MCParticle.h:436
float getMass() const
Return the particle mass in GeV.
Definition: MCParticle.h:124
void setProductionVertex(const ROOT::Math::XYZVector &vertex)
Set production vertex position.
Definition: MCParticle.h:385
ROOT::Math::PxPyPzEVector get4Vector() const
Return 4Vector of particle.
Definition: MCParticle.h:196
void setPDG(int pdg)
Set PDG code of the particle.
Definition: MCParticle.h:324
void set4Vector(const ROOT::Math::PxPyPzEVector &p4)
Sets the 4Vector of particle.
Definition: MCParticle.h:427
void setMomentum(const ROOT::Math::XYZVector &momentum)
Set particle momentum.
Definition: MCParticle.h:406
void setStatus(unsigned short int status)
Set Status code for the particle.
Definition: MCParticle.h:335
void setProductionTime(float time)
Set production time.
Definition: MCParticle.h:373
void setMassFromPDG()
Sets the mass for the particle from the particle's PDG code.
Definition: MCParticle.cc:28
Class to hold Lorentz transformations from/to CMS and boost vector.
double getCMSEnergy() const
Returns CMS energy of e+e- (aka.
const ROOT::Math::LorentzRotation rotateLabToCms() const
Returns Lorentz transformation from Lab to CMS.
static ROOT::Math::PxPyPzMVector cmsToLab(const ROOT::Math::PxPyPzMVector &vec)
Transforms Lorentz vector into Laboratory System.
const ROOT::Math::LorentzRotation rotateCmsToLab() const
Returns Lorentz transformation from CMS to Lab.
Class to store reconstructed particles.
Definition: Particle.h:76
void appendDaughter(const Particle *daughter, const bool updateType=true, const int daughterProperty=c_Ordinary)
Appends index of daughter to daughters index array.
Definition: Particle.cc:707
void setVertex(const ROOT::Math::XYZVector &vertex)
Sets position (decay vertex)
Definition: Particle.h:306
double getEnergy() const
Returns total energy.
Definition: Particle.h:555
double getPDGMass(void) const
Returns uncertainty on the invariant mass (requires valid momentum error matrix)
Definition: Particle.cc:635
ROOT::Math::PxPyPzEVector get4Vector() const
Returns Lorentz vector.
Definition: Particle.h:567
void addExtraInfo(const std::string &name, double value)
Sets the user-defined data of given name to the given value.
Definition: Particle.cc:1421
@ c_Unflavored
Is its own antiparticle or we don't know whether it is a particle/antiparticle.
Definition: Particle.h:97
@ c_Flavored
Is either particle or antiparticle.
Definition: Particle.h:98
double getP() const
Returns momentum magnitude (same as getMomentumMagnitude but with shorter name)
Definition: Particle.h:598
const Particle * getDaughter(unsigned i) const
Returns a pointer to the i-th daughter particle.
Definition: Particle.cc:662
double getMass() const
Returns invariant mass (= nominal for FS particles)
Definition: Particle.h:527
static const ReferenceFrame & GetCurrent()
Get current rest frame.
void addRelationTo(const RelationsInterface< BASE > *object, float weight=1.0, const std::string &namedRelation="") const
Add a relation from this object to another object (with caching).
int getArrayIndex() const
Returns this object's array index (in StoreArray), or -1 if not found.
TO * getRelatedTo(const std::string &name="", const std::string &namedRelation="") const
Get the object to which this object has a relation.
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
bool create(bool replace=false)
Create a default object in the data store.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:246
void clear() override
Delete all entries in this array.
Definition: StoreArray.h:207
bool registerRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut, const std::string &namedRelation="") const
Register a relation to the given StoreArray.
Definition: StoreArray.h:140
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:95
Class that bundles various TrackFitResults.
Definition: Track.h:25
void setTrackFitResultIndex(const Const::ChargedStable &chargedStable, short index)
Set an index (for positive values) or unavailability-code (index = -1) for a specific mass hypothesis...
Definition: Track.h:188
The Unit class.
Definition: Unit.h:40
A template class to apply the reference frame.
Object holding information for V0s.
Definition: V0.h:34
const Var * getVariable(std::string name)
Get the variable belonging to the given key.
Definition: Manager.cc:58
static Manager & Instance()
get singleton instance.
Definition: Manager.cc:26
static Gearbox & getInstance()
Return reference to the Gearbox instance.
Definition: Gearbox.cc:81
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
GraphParticle & addParticle()
Add new particle to the graph.
double charge(int pdgCode)
Returns electric charge of a particle with given pdg code.
Definition: EvtPDLUtil.cc:44
Abstract base class for different kinds of events.
STL namespace.
A variable returning a floating-point value for a given Particle.
Definition: Manager.h:145
FunctionPtr function
Pointer to function.
Definition: Manager.h:146