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