Belle II Software development
variables.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <analysis/variables/Variables.h>
10#include <analysis/variables/BasicParticleInformation.h>
11#include <analysis/variables/VertexVariables.h>
12#include <analysis/variables/PIDVariables.h>
13#include <analysis/variables/TrackVariables.h>
14
15#include <analysis/VariableManager/Manager.h>
16#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 TEST_F(MetaVariableTest, useMCancestorBRestFrame)
992 {
994 StoreArray<Particle> particles;
995 StoreArray<MCParticle> mcparticles;
996 particles.registerInDataStore();
997 mcparticles.registerInDataStore();
998 particles.registerRelationTo(mcparticles);
999 MCParticleGraph mcGraph;
1000 // MC mother of the MC particle
1001 MCParticleGraph::GraphParticle& mcMother = mcGraph.addParticle();
1002 // MC particle of the reconstructed one
1003 MCParticleGraph::GraphParticle& mcParticle = mcGraph.addParticle();
1004 mcParticle.comesFrom(mcMother);
1005 mcGraph.generateList();
1006 // Reconstructed particle
1007 Particle particle({ 0.1, -0.4, 0.8, 1.0 }, 411);
1008 auto* p = particles.appendNew(particle);
1009 p->setVertex(XYZVector(1.0, 2.0, 2.0));
1010 p->addRelationTo(mcparticles[1]);
1011
1012 mcparticles[1]->setPDG(411);
1013
1014 // MC mother of the MC particle
1015 mcparticles[0]->setMomentum(XYZVector(0.0, 0.0, 0.1));
1016 mcparticles[0]->setStatus(MCParticle::c_PrimaryParticle);
1017 mcparticles[0]->setPDG(511);
1018 mcparticles[0]->setMassFromPDG();
1020
1021 const Manager::Var* var = Manager::Instance().getVariable("useMCancestorBRestFrame(p)");
1022 ASSERT_NE(var, nullptr);
1023 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0.88333338);
1024
1025 var = Manager::Instance().getVariable("useMCancestorBRestFrame(E)");
1026 ASSERT_NE(var, nullptr);
1027 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0.98502684);
1028
1029 var = Manager::Instance().getVariable("useMCancestorBRestFrame(distance)");
1030 ASSERT_NE(var, nullptr);
1031 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 3.0007174);
1032 }
1033
1034 TEST_F(MetaVariableTest, extraInfo)
1035 {
1036 Particle p({ 0.1, -0.4, 0.8, 1.0 }, 11);
1037 p.addExtraInfo("pi", 3.14);
1038
1039 const Manager::Var* var = Manager::Instance().getVariable("extraInfo(pi)");
1040 ASSERT_NE(var, nullptr);
1041 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 3.14);
1042
1043 // If nullptr is given, NaN is returned
1044 EXPECT_TRUE(std::isnan(std::get<double>(var->function(nullptr))));
1045 }
1046
1047 TEST_F(MetaVariableTest, eventExtraInfo)
1048 {
1049 StoreObjPtr<EventExtraInfo> eventExtraInfo;
1050 if (not eventExtraInfo.isValid())
1051 eventExtraInfo.create();
1052 eventExtraInfo->addExtraInfo("pi", 3.14);
1053 const Manager::Var* var = Manager::Instance().getVariable("eventExtraInfo(pi)");
1054 ASSERT_NE(var, nullptr);
1055 EXPECT_FLOAT_EQ(std::get<double>(var->function(nullptr)), 3.14);
1056 }
1057
1058 TEST_F(MetaVariableTest, eventCached)
1059 {
1060 const Manager::Var* var = Manager::Instance().getVariable("eventCached(constant(3.14))");
1061 ASSERT_NE(var, nullptr);
1062 EXPECT_FLOAT_EQ(std::get<double>(var->function(nullptr)), 3.14);
1063 StoreObjPtr<EventExtraInfo> eventExtraInfo;
1064 EXPECT_TRUE(eventExtraInfo.isValid());
1065 EXPECT_TRUE(eventExtraInfo->hasExtraInfo("__constant__bo3__pt14__bc"));
1066 EXPECT_FLOAT_EQ(eventExtraInfo->getExtraInfo("__constant__bo3__pt14__bc"), 3.14);
1067 eventExtraInfo->addExtraInfo("__eventExtraInfo__bopi__bc", 3.14);
1068 var = Manager::Instance().getVariable("eventCached(eventExtraInfo(pi))");
1069 ASSERT_NE(var, nullptr);
1070 EXPECT_FLOAT_EQ(std::get<double>(var->function(nullptr)), 3.14);
1071 }
1072
1073 TEST_F(MetaVariableTest, particleCached)
1074 {
1075 Particle p({ 0.1, -0.4, 0.8, 2.0 }, 11);
1076 const Manager::Var* var = Manager::Instance().getVariable("particleCached(px)");
1077 ASSERT_NE(var, nullptr);
1078 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.1);
1079 EXPECT_TRUE(p.hasExtraInfo("__px"));
1080 EXPECT_FLOAT_EQ(p.getExtraInfo("__px"), 0.1);
1081 p.addExtraInfo("__py", -0.5); // NOT -0.4 because we want to see if the cache is used instead of py!
1082 var = Manager::Instance().getVariable("particleCached(py)");
1083 ASSERT_NE(var, nullptr);
1084 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -0.5);
1085 }
1086
1087 TEST_F(MetaVariableTest, basicMathTest)
1088 {
1089 Particle p({ 0.1, -0.4, 0.8, 2.0 }, 411);
1090
1091 const Manager::Var* var = Manager::Instance().getVariable("abs(py)");
1092 ASSERT_NE(var, nullptr);
1093 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.4);
1094
1095 var = Manager::Instance().getVariable("min(E, pz)");
1096 ASSERT_NE(var, nullptr);
1097 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.8);
1098
1099 var = Manager::Instance().getVariable("max(E, pz)");
1100 ASSERT_NE(var, nullptr);
1101 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 2.0);
1102
1103 var = Manager::Instance().getVariable("log10(px)");
1104 ASSERT_NE(var, nullptr);
1105 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -1.0);
1106
1107 // sin 30 = 0.5
1108 var = Manager::Instance().getVariable("sin(0.5235987755983)");
1109 ASSERT_NE(var, nullptr);
1110 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.5);
1111
1112 // sin 90 = 1
1113 var = Manager::Instance().getVariable("sin(1.5707963267948966)");
1114 ASSERT_NE(var, nullptr);
1115 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.0);
1116
1117 // asin 1 = 90
1118 var = Manager::Instance().getVariable("asin(1.0)");
1119 ASSERT_NE(var, nullptr);
1120 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.5707963267948966);
1121
1122 // cos 60 = 0.5
1123 var = Manager::Instance().getVariable("cos(1.0471975511965976)");
1124 ASSERT_NE(var, nullptr);
1125 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.5);
1126
1127 // acos 0 = 90
1128 var = Manager::Instance().getVariable("acos(0)");
1129 ASSERT_NE(var, nullptr);
1130 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.5707963267948966);
1131
1132 }
1133
1134 TEST_F(MetaVariableTest, formula)
1135 {
1136 // see also unit tests in framework/formula_parser.cc
1137 //
1138 // keep particle-based tests here, and operator precedence tests (etc) in
1139 // framework with the parser itself
1140
1141 Particle p({ 0.1, -0.4, 0.8, 2.0 }, -411);
1142
1143 const Manager::Var* var = Manager::Instance().getVariable("formula(px + py)");
1144 ASSERT_NE(var, nullptr);
1145 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -0.3);
1146
1147 var = Manager::Instance().getVariable("formula(px - py)");
1148 ASSERT_NE(var, nullptr);
1149 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.5);
1150
1151 var = Manager::Instance().getVariable("formula(px * py)");
1152 ASSERT_NE(var, nullptr);
1153 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -0.04);
1154
1155 var = Manager::Instance().getVariable("formula(py / px)");
1156 ASSERT_NE(var, nullptr);
1157 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -4.0);
1158
1159 var = Manager::Instance().getVariable("formula(px ^ E)");
1160 ASSERT_NE(var, nullptr);
1161 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.01);
1162
1163 var = Manager::Instance().getVariable("formula(px * py + pz)");
1164 ASSERT_NE(var, nullptr);
1165 EXPECT_NEAR(std::get<double>(var->function(&p)), 0.76, 1e-6);
1166
1167 var = Manager::Instance().getVariable("formula(pz + px * py)");
1168 ASSERT_NE(var, nullptr);
1169 EXPECT_NEAR(std::get<double>(var->function(&p)), 0.76, 1e-6);
1170
1171 var = Manager::Instance().getVariable("formula(pt)");
1172 ASSERT_NE(var, nullptr);
1173 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.41231057);
1174 double pt = std::get<double>(var->function(&p));
1175
1176 var = Manager::Instance().getVariable("formula((px**2 + py**2)**(1/2))");
1177 ASSERT_NE(var, nullptr);
1178 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), pt);
1179
1180 var = Manager::Instance().getVariable("formula(charge)");
1181 ASSERT_NE(var, nullptr);
1182 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -1.0);
1183
1184 var = Manager::Instance().getVariable("formula(charge**2)");
1185 ASSERT_NE(var, nullptr);
1186 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.0);
1187
1188 var = Manager::Instance().getVariable("formula(charge^2)");
1189 ASSERT_NE(var, nullptr);
1190 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.0);
1191
1192 var = Manager::Instance().getVariable("formula(PDG * charge)");
1193 ASSERT_NE(var, nullptr);
1194 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 411.0);
1195
1196 var = Manager::Instance().getVariable("formula(PDG**2 * charge)");
1197 ASSERT_NE(var, nullptr);
1198 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -168921.0);
1199
1200 var = Manager::Instance().getVariable("formula(10.58 - (px + py + pz - E)**2)");
1201 ASSERT_NE(var, nullptr);
1202 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 8.33);
1203
1204 var = Manager::Instance().getVariable("formula(-10.58 + (px + py + pz - E)**2)");
1205 ASSERT_NE(var, nullptr);
1206 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -8.33);
1207
1208 var = Manager::Instance().getVariable("formula(-1.0 * PDG)");
1209 ASSERT_NE(var, nullptr);
1210 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 411);
1211 }
1212
1213 TEST_F(MetaVariableTest, passesCut)
1214 {
1215 Particle p({ 0.1, -0.4, 0.8, 2.0 }, 411);
1216 Particle p2({ 0.1, -0.4, 0.8, 4.0 }, 411);
1217
1218 const Manager::Var* var = Manager::Instance().getVariable("passesCut(E < 3)");
1219 ASSERT_NE(var, nullptr);
1220 EXPECT_TRUE(std::get<bool>(var->function(&p)));
1221 EXPECT_FALSE(std::get<bool>(var->function(&p2)));
1222 // 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
1223
1224 }
1225
1226 TEST_F(MetaVariableTest, unmask)
1227 {
1229 StoreArray<MCParticle> mcParticles;
1230 StoreArray<Particle> particles;
1231 particles.registerInDataStore();
1232 mcParticles.registerInDataStore();
1233 particles.registerRelationTo(mcParticles);
1235
1236 // Create MC graph for B -> (muon -> electron + muon_neutrino) + anti_muon_neutrino
1237 MCParticleGraph mcGraph;
1238
1239 MCParticleGraph::GraphParticle& graphParticleGrandMother = mcGraph.addParticle();
1240
1241 MCParticleGraph::GraphParticle& graphParticleMother = mcGraph.addParticle();
1242 MCParticleGraph::GraphParticle& graphParticleAunt = mcGraph.addParticle();
1243
1244 MCParticleGraph::GraphParticle& graphParticleDaughter1 = mcGraph.addParticle();
1245 MCParticleGraph::GraphParticle& graphParticleDaughter2 = mcGraph.addParticle();
1246
1247 graphParticleGrandMother.setPDG(-521);
1248 graphParticleMother.setPDG(Const::muon.getPDGCode());
1249 graphParticleAunt.setPDG(-14);
1250 graphParticleDaughter1.setPDG(Const::electron.getPDGCode());
1251 graphParticleDaughter2.setPDG(14);
1252
1253 graphParticleMother.comesFrom(graphParticleGrandMother);
1254 graphParticleAunt.comesFrom(graphParticleGrandMother);
1255 graphParticleDaughter1.comesFrom(graphParticleMother);
1256 graphParticleDaughter2.comesFrom(graphParticleMother);
1257 mcGraph.generateList();
1258
1259
1260 // Get MC Particles from StoreArray
1261 auto* mcGrandMother = mcParticles[0];
1262 mcGrandMother->setStatus(MCParticle::c_PrimaryParticle);
1263
1264 auto* mcMother = mcParticles[1];
1265 mcMother->setStatus(MCParticle::c_PrimaryParticle);
1266
1267 auto* mcAunt = mcParticles[2];
1268 mcAunt->setStatus(MCParticle::c_PrimaryParticle);
1269
1270 auto* mcDaughter1 = mcParticles[3];
1271 mcDaughter1->setStatus(MCParticle::c_PrimaryParticle);
1272
1273 auto* mcDaughter2 = mcParticles[4];
1274 mcDaughter2->setStatus(MCParticle::c_PrimaryParticle);
1275
1276 auto* pGrandMother = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), -521);
1277 pGrandMother->addRelationTo(mcGrandMother);
1278
1279 auto* pMother = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 13);
1280 pMother->addRelationTo(mcMother);
1281
1282
1283 pMother->writeExtraInfo("mcErrors", 8);
1284 pGrandMother->writeExtraInfo("mcErrors", 8 | 16);
1285 const Manager::Var* var1 = Manager::Instance().getVariable("unmask(mcErrors, 8)");
1286 const Manager::Var* var2 = Manager::Instance().getVariable("unmask(mcErrors, 8, 16, 32, 64)");
1287 ASSERT_NE(var1, nullptr);
1288 EXPECT_FLOAT_EQ(std::get<double>(var1->function(pMother)), 0);
1289 EXPECT_FLOAT_EQ(std::get<double>(var1->function(pGrandMother)), 16);
1290 ASSERT_NE(var2, nullptr);
1291 EXPECT_FLOAT_EQ(std::get<double>(var2->function(pMother)), 0);
1292 EXPECT_FLOAT_EQ(std::get<double>(var2->function(pGrandMother)), 0);
1293
1294
1295 pMother->writeExtraInfo("mcErrors", 8 | 128);
1296 pGrandMother->writeExtraInfo("mcErrors", 8 | 16 | 512);
1297 ASSERT_NE(var1, nullptr);
1298 EXPECT_FLOAT_EQ(std::get<double>(var1->function(pMother)), 128);
1299 EXPECT_FLOAT_EQ(std::get<double>(var1->function(pGrandMother)), 16 | 512);
1300 ASSERT_NE(var2, nullptr);
1301 EXPECT_FLOAT_EQ(std::get<double>(var2->function(pMother)), 128);
1302 EXPECT_FLOAT_EQ(std::get<double>(var2->function(pGrandMother)), 512);
1303
1304 // unmask variable needs at least two arguments
1305 EXPECT_B2FATAL(Manager::Instance().getVariable("unmask(mcErrors)"));
1306
1307 // all but the first argument have to be integers
1308 EXPECT_B2FATAL(Manager::Instance().getVariable("unmask(mcErrors, NOTINT)"));
1309 }
1310
1311 TEST_F(MetaVariableTest, conditionalVariableSelector)
1312 {
1313 Particle p({ 0.1, -0.4, 0.8, 2.0 }, 411);
1314
1315 const Manager::Var* var = Manager::Instance().getVariable("conditionalVariableSelector(E>1, px, py)");
1316 ASSERT_NE(var, nullptr);
1317 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.1);
1318
1319 var = Manager::Instance().getVariable("conditionalVariableSelector(E<1, px, py)");
1320 ASSERT_NE(var, nullptr);
1321 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), -0.4);
1322
1323 }
1324
1325 TEST_F(MetaVariableTest, nCleanedTracks)
1326 {
1328 StoreArray<TrackFitResult> track_fit_results;
1329 StoreArray<Track> tracks;
1330 track_fit_results.registerInDataStore();
1331 tracks.registerInDataStore();
1333
1334 Particle p({ 0.1, -0.4, 0.8, 2.0 }, 11);
1335 Particle p2({ 0.1, -0.4, 0.8, 4.0 }, 11);
1336
1337 track_fit_results.appendNew(ROOT::Math::XYZVector(0.1, 0.1, 0.1), ROOT::Math::XYZVector(0.1, 0.0, 0.0),
1338 TMatrixDSym(6), 1, Const::pion, 0.01, 1.5, 0, 0, 0);
1339 track_fit_results.appendNew(ROOT::Math::XYZVector(0.1, 0.1, 0.1), ROOT::Math::XYZVector(0.15, 0.0, 0.0),
1340 TMatrixDSym(6), 1, Const::pion, 0.01, 1.5, 0, 0, 0);
1341 track_fit_results.appendNew(ROOT::Math::XYZVector(0.1, 0.1, 0.1), ROOT::Math::XYZVector(0.4, 0.0, 0.0),
1342 TMatrixDSym(6), 1, Const::pion, 0.01, 1.5, 0, 0, 0);
1343 track_fit_results.appendNew(ROOT::Math::XYZVector(0.1, 0.1, 0.1), ROOT::Math::XYZVector(0.6, 0.0, 0.0),
1344 TMatrixDSym(6), 1, Const::pion, 0.01, 1.5, 0, 0, 0);
1345
1346 tracks.appendNew()->setTrackFitResultIndex(Const::pion, 0);
1347 tracks.appendNew()->setTrackFitResultIndex(Const::pion, 1);
1348 tracks.appendNew()->setTrackFitResultIndex(Const::pion, 2);
1349 tracks.appendNew()->setTrackFitResultIndex(Const::pion, 3);
1350
1351 const Manager::Var* var1 = Manager::Instance().getVariable("nCleanedTracks(p > 0.5)");
1352 EXPECT_FLOAT_EQ(std::get<int>(var1->function(nullptr)), 1);
1353
1354 const Manager::Var* var2 = Manager::Instance().getVariable("nCleanedTracks(p > 0.2)");
1355 EXPECT_FLOAT_EQ(std::get<int>(var2->function(nullptr)), 2);
1356
1357 const Manager::Var* var3 = Manager::Instance().getVariable("nCleanedTracks()");
1358 EXPECT_FLOAT_EQ(std::get<int>(var3->function(nullptr)), 4);
1359
1360
1361 }
1362
1363 TEST_F(MetaVariableTest, NumberOfMCParticlesInEvent)
1364 {
1365 Particle p({ 0.1, -0.4, 0.8, 2.0 }, 11);
1366 Particle p2({ 0.1, -0.4, 0.8, 4.0 }, 11);
1367
1368 StoreArray<MCParticle> mcParticles;
1369 auto* mcParticle = mcParticles.appendNew();
1370 mcParticle->setPDG(Const::electron.getPDGCode());
1372 mcParticle = mcParticles.appendNew();
1373 mcParticle->setPDG(Const::photon.getPDGCode());
1375 mcParticle = mcParticles.appendNew();
1376 mcParticle->setPDG(-Const::electron.getPDGCode());
1378 mcParticle = mcParticles.appendNew();
1379 mcParticle->setPDG(Const::electron.getPDGCode());
1380
1381
1382 const Manager::Var* var = Manager::Instance().getVariable("NumberOfMCParticlesInEvent(11)");
1383 ASSERT_NE(var, nullptr);
1384 EXPECT_EQ(std::get<int>(var->function(nullptr)), 2);
1385
1386 }
1387
1388 TEST_F(MetaVariableTest, daughterInvM)
1389 {
1390 PxPyPzEVector momentum;
1391 const int nDaughters = 6;
1392 StoreArray<Particle> particles;
1393 std::vector<int> daughterIndices;
1394 for (int i = 0; i < nDaughters; i++) {
1395 Particle d(PxPyPzEVector(2, 2, 2, 4.0), (i % 2) ? 213 : -213);
1396 momentum += d.get4Vector();
1397 Particle* newDaughters = particles.appendNew(d);
1398 daughterIndices.push_back(newDaughters->getArrayIndex());
1399 }
1400 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1401
1402 const Manager::Var* var = Manager::Instance().getVariable("daughterInvM(6,5)");
1403 ASSERT_NE(var, nullptr);
1404 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
1405
1406 var = Manager::Instance().getVariable("daughterInvM(0, 1)");
1407 ASSERT_NE(var, nullptr);
1408 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 4.0);
1409
1410 var = Manager::Instance().getVariable("daughterInvM(0, 1, 2)");
1411 ASSERT_NE(var, nullptr);
1412 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 6.0);
1413 }
1414
1415 TEST_F(MetaVariableTest, daughter)
1416 {
1417 PxPyPzEVector momentum;
1418 const int nDaughters = 6;
1419 StoreArray<Particle> particles;
1420 std::vector<int> daughterIndices;
1421 for (int i = 0; i < nDaughters; i++) {
1422 Particle d(PxPyPzEVector(i * 1.0, 1, 1, 1), (i % 2) ? 211 : -211);
1423 momentum += d.get4Vector();
1424 Particle* newDaughters = particles.appendNew(d);
1425 daughterIndices.push_back(newDaughters->getArrayIndex());
1426 }
1427 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1428
1429 const Manager::Var* var = Manager::Instance().getVariable("daughter(6, px)");
1430 ASSERT_NE(var, nullptr);
1431 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
1432
1433 var = Manager::Instance().getVariable("daughter(0, px)");
1434 ASSERT_NE(var, nullptr);
1435 EXPECT_NEAR(std::get<double>(var->function(p)), 0.0, 1e-6);
1436
1437 var = Manager::Instance().getVariable("daughter(1, px)");
1438 ASSERT_NE(var, nullptr);
1439 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 1.0);
1440
1441 var = Manager::Instance().getVariable("daughter(2, px)");
1442 ASSERT_NE(var, nullptr);
1443 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 2.0);
1444 }
1445
1446 TEST_F(MetaVariableTest, mcDaughter)
1447 {
1449 StoreArray<MCParticle> mcParticles;
1450 StoreArray<Particle> particles;
1451 particles.registerInDataStore();
1452 mcParticles.registerInDataStore();
1453 particles.registerRelationTo(mcParticles);
1455
1456 // Create MC graph for B -> (muon -> electron + muon_neutrino) + anti_muon_neutrino
1457 MCParticleGraph mcGraph;
1458
1459 MCParticleGraph::GraphParticle& graphParticleGrandMother = mcGraph.addParticle();
1460
1461 MCParticleGraph::GraphParticle& graphParticleMother = mcGraph.addParticle();
1462 MCParticleGraph::GraphParticle& graphParticleAunt = mcGraph.addParticle();
1463
1464 MCParticleGraph::GraphParticle& graphParticleDaughter1 = mcGraph.addParticle();
1465 MCParticleGraph::GraphParticle& graphParticleDaughter2 = mcGraph.addParticle();
1466
1467 graphParticleGrandMother.setPDG(-521);
1468 graphParticleMother.setPDG(Const::muon.getPDGCode());
1469 graphParticleAunt.setPDG(-14);
1470 graphParticleDaughter1.setPDG(Const::electron.getPDGCode());
1471 graphParticleDaughter2.setPDG(14);
1472
1473 graphParticleMother.comesFrom(graphParticleGrandMother);
1474 graphParticleAunt.comesFrom(graphParticleGrandMother);
1475 graphParticleDaughter1.comesFrom(graphParticleMother);
1476 graphParticleDaughter2.comesFrom(graphParticleMother);
1477 mcGraph.generateList();
1478
1479 // Get MC Particles from StoreArray
1480 auto* mcGrandMother = mcParticles[0];
1481 mcGrandMother->setStatus(MCParticle::c_PrimaryParticle);
1482
1483 auto* mcMother = mcParticles[1];
1484 mcMother->setStatus(MCParticle::c_PrimaryParticle);
1485
1486 auto* mcAunt = mcParticles[2];
1487 mcAunt->setStatus(MCParticle::c_PrimaryParticle);
1488
1489 auto* mcDaughter1 = mcParticles[3];
1490 mcDaughter1->setStatus(MCParticle::c_PrimaryParticle);
1491
1492 auto* mcDaughter2 = mcParticles[4];
1493 mcDaughter2->setStatus(MCParticle::c_PrimaryParticle);
1494
1495 auto* pGrandMother = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), -521);
1496 pGrandMother->addRelationTo(mcGrandMother);
1497
1498 auto* pMother = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 13);
1499 pMother->addRelationTo(mcMother);
1500
1501 // Test for particle that has no MC match
1502 auto* p_noMC = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 13);
1503
1504 // Test for particle that has MC match, but MC match has no daughter
1505 auto* p_noDaughter = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
1506 p_noDaughter->addRelationTo(mcDaughter1);
1507
1508 const Manager::Var* var = Manager::Instance().getVariable("mcDaughter(0, PDG)");
1509 ASSERT_NE(var, nullptr);
1510 EXPECT_FLOAT_EQ(std::get<double>(var->function(pGrandMother)), 13);
1511 EXPECT_FLOAT_EQ(std::get<double>(var->function(pMother)), 11);
1512 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p_noMC))));
1513 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p_noDaughter))));
1514 var = Manager::Instance().getVariable("mcDaughter(1, PDG)");
1515 EXPECT_FLOAT_EQ(std::get<double>(var->function(pGrandMother)), -14);
1516 EXPECT_FLOAT_EQ(std::get<double>(var->function(pMother)), 14);
1517 // Test for particle where mc daughter index is out of range of mc daughters
1518 var = Manager::Instance().getVariable("mcDaughter(2, PDG)");
1519 EXPECT_TRUE(std::isnan(std::get<double>(var->function(pGrandMother))));
1520 EXPECT_TRUE(std::isnan(std::get<double>(var->function(pMother))));
1521 // Test nested application of mcDaughter
1522 var = Manager::Instance().getVariable("mcDaughter(0, mcDaughter(0, PDG))");
1523 EXPECT_FLOAT_EQ(std::get<double>(var->function(pGrandMother)), 11);
1524 EXPECT_TRUE(std::isnan(std::get<double>(var->function(pMother))));
1525 var = Manager::Instance().getVariable("mcDaughter(0, mcDaughter(1, PDG))");
1526 EXPECT_FLOAT_EQ(std::get<double>(var->function(pGrandMother)), 14);
1527 var = Manager::Instance().getVariable("mcDaughter(0, mcDaughter(2, PDG))");
1528 EXPECT_TRUE(std::isnan(std::get<double>(var->function(pGrandMother))));
1529 var = Manager::Instance().getVariable("mcDaughter(1, mcDaughter(0, PDG))");
1530 EXPECT_TRUE(std::isnan(std::get<double>(var->function(pGrandMother))));
1531 }
1532
1533 TEST_F(MetaVariableTest, mcMother)
1534 {
1536 StoreArray<MCParticle> mcParticles;
1537 StoreArray<Particle> particles;
1538 particles.registerInDataStore();
1539 mcParticles.registerInDataStore();
1540 particles.registerRelationTo(mcParticles);
1542
1543 // Create MC graph for B -> (muon -> electron + muon_neutrino) + anti_muon_neutrino
1544 MCParticleGraph mcGraph;
1545
1546 MCParticleGraph::GraphParticle& graphParticleGrandMother = mcGraph.addParticle();
1547
1548 MCParticleGraph::GraphParticle& graphParticleMother = mcGraph.addParticle();
1549 MCParticleGraph::GraphParticle& graphParticleAunt = mcGraph.addParticle();
1550
1551 MCParticleGraph::GraphParticle& graphParticleDaughter1 = mcGraph.addParticle();
1552 MCParticleGraph::GraphParticle& graphParticleDaughter2 = mcGraph.addParticle();
1553
1554 graphParticleGrandMother.setPDG(-521);
1555 graphParticleMother.setPDG(Const::muon.getPDGCode());
1556 graphParticleAunt.setPDG(-14);
1557 graphParticleDaughter1.setPDG(Const::electron.getPDGCode());
1558 graphParticleDaughter2.setPDG(14);
1559
1560 graphParticleMother.comesFrom(graphParticleGrandMother);
1561 graphParticleAunt.comesFrom(graphParticleGrandMother);
1562 graphParticleDaughter1.comesFrom(graphParticleMother);
1563 graphParticleDaughter2.comesFrom(graphParticleMother);
1564
1565 mcGraph.generateList();
1566
1567 // Get MC Particles from StoreArray
1568 auto* mcGrandMother = mcParticles[0];
1569 mcGrandMother->setStatus(MCParticle::c_PrimaryParticle);
1570
1571 auto* mcMother = mcParticles[1];
1572 mcMother->setStatus(MCParticle::c_PrimaryParticle);
1573
1574 auto* mcAunt = mcParticles[2];
1575 mcAunt->setStatus(MCParticle::c_PrimaryParticle);
1576
1577 auto* mcDaughter1 = mcParticles[3];
1578 mcDaughter1->setStatus(MCParticle::c_PrimaryParticle);
1579
1580 auto* mcDaughter2 = mcParticles[4];
1581 mcDaughter2->setStatus(MCParticle::c_PrimaryParticle);
1582
1583 auto* p1 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
1584 p1->addRelationTo(mcDaughter1);
1585
1586 auto* p2 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 14);
1587 p2->addRelationTo(mcDaughter2);
1588
1589 auto* pMother = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 13);
1590 pMother->addRelationTo(mcMother);
1591
1592 // For test of particle that has no MC match
1593 auto* p_noMC = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
1594
1595 // For test of particle that has MC match, but MC match has no mother
1596 auto* p_noMother = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), -521);
1597 p_noMother->addRelationTo(mcGrandMother);
1598
1599 const Manager::Var* var = Manager::Instance().getVariable("mcMother(PDG)");
1600 ASSERT_NE(var, nullptr);
1601 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), 13);
1602 EXPECT_FLOAT_EQ(std::get<double>(var->function(p2)), 13);
1603 EXPECT_FLOAT_EQ(std::get<double>(var->function(pMother)), -521);
1604 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p_noMC))));
1605 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p_noMother))));
1606
1607 // Test if nested calls of mcMother work correctly
1608 var = Manager::Instance().getVariable("mcMother(mcMother(PDG))");
1609 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), -521);
1610 }
1611
1612 TEST_F(MetaVariableTest, genParticle)
1613 {
1615 StoreArray<MCParticle> mcParticles;
1616 StoreArray<Particle> particles;
1617 particles.registerInDataStore();
1618 mcParticles.registerInDataStore();
1619 particles.registerRelationTo(mcParticles);
1621
1622 // Create MC graph for Upsilon(4S) -> (B^- -> electron + anti_electron_neutrino) + B^+
1623 MCParticleGraph mcGraph;
1624
1625 MCParticleGraph::GraphParticle& graphParticleGrandMother = mcGraph.addParticle();
1626
1627 MCParticleGraph::GraphParticle& graphParticleMother = mcGraph.addParticle();
1628 MCParticleGraph::GraphParticle& graphParticleAunt = mcGraph.addParticle();
1629
1630 MCParticleGraph::GraphParticle& graphParticleDaughter1 = mcGraph.addParticle();
1631 MCParticleGraph::GraphParticle& graphParticleDaughter2 = mcGraph.addParticle();
1632
1633 graphParticleGrandMother.setPDG(300553);
1634 graphParticleMother.setPDG(-521);
1635 graphParticleAunt.setPDG(521);
1636 graphParticleDaughter1.setPDG(Const::electron.getPDGCode());
1637 graphParticleDaughter2.setPDG(-12);
1638
1639 graphParticleGrandMother.setMomentum(0.0, 0.0, 0.4);
1640 graphParticleMother.setMomentum(1.1, 1.3, 1.5);
1641
1642 graphParticleMother.comesFrom(graphParticleGrandMother);
1643 graphParticleAunt.comesFrom(graphParticleGrandMother);
1644 graphParticleDaughter1.comesFrom(graphParticleMother);
1645 graphParticleDaughter2.comesFrom(graphParticleMother);
1646
1647 mcGraph.generateList();
1648
1649 // Get MC Particles from StoreArray
1650 auto* mcGrandMother = mcParticles[0];
1651 mcGrandMother->setStatus(MCParticle::c_PrimaryParticle);
1652
1653 auto* mcMother = mcParticles[1];
1654 mcMother->setStatus(MCParticle::c_PrimaryParticle);
1655
1656 auto* mcAunt = mcParticles[2];
1657 mcAunt->setStatus(MCParticle::c_PrimaryParticle);
1658
1659 auto* mcDaughter1 = mcParticles[3];
1660 mcDaughter1->setStatus(MCParticle::c_PrimaryParticle);
1661
1662 auto* mcDaughter2 = mcParticles[4];
1663 mcDaughter2->setStatus(MCParticle::c_PrimaryParticle);
1664
1665 auto* p1 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
1666 p1->addRelationTo(mcDaughter1);
1667
1668 // For test of particle that has no MC match
1669 auto* p_noMC = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 211);
1670
1671 const Manager::Var* var = Manager::Instance().getVariable("genParticle(0, PDG)");
1672 ASSERT_NE(var, nullptr);
1673 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), 300553);
1674 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), 300553);
1675
1676 var = Manager::Instance().getVariable("genParticle(0, matchedMC(pz))");
1677 ASSERT_NE(var, nullptr);
1678 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), 0.4);
1679 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), 0.4);
1680
1681 var = Manager::Instance().getVariable("genParticle(0, mcDaughter(0, PDG))");
1682 ASSERT_NE(var, nullptr);
1683 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), -521);
1684 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), -521);
1685
1686 var = Manager::Instance().getVariable("genParticle(0, mcDaughter(0, matchedMC(px)))");
1687 ASSERT_NE(var, nullptr);
1688 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), 1.1);
1689 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), 1.1);
1690
1691 var = Manager::Instance().getVariable("genParticle(1, PDG)");
1692 ASSERT_NE(var, nullptr);
1693 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), -521);
1694 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), -521);
1695
1696 var = Manager::Instance().getVariable("genParticle(4, PDG)");
1697 ASSERT_NE(var, nullptr);
1698 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), -12);
1699 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), -12);
1700
1701 var = Manager::Instance().getVariable("genParticle(5, PDG)");
1702 ASSERT_NE(var, nullptr);
1703 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p1))));
1704 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p_noMC))));
1705 }
1706
1707 TEST_F(MetaVariableTest, genUpsilon4S)
1708 {
1710 StoreArray<MCParticle> mcParticles;
1711 StoreArray<Particle> particles;
1712 particles.registerInDataStore();
1713 mcParticles.registerInDataStore();
1714 particles.registerRelationTo(mcParticles);
1716
1717 // Create MC graph for Upsilon(4S) -> (B^- -> electron + anti_electron_neutrino) + B^+
1718 MCParticleGraph mcGraph;
1719
1720 MCParticleGraph::GraphParticle& graphParticleGrandMother = mcGraph.addParticle();
1721
1722 MCParticleGraph::GraphParticle& graphParticleMother = mcGraph.addParticle();
1723 MCParticleGraph::GraphParticle& graphParticleAunt = mcGraph.addParticle();
1724
1725 MCParticleGraph::GraphParticle& graphParticleDaughter1 = mcGraph.addParticle();
1726 MCParticleGraph::GraphParticle& graphParticleDaughter2 = mcGraph.addParticle();
1727
1728 graphParticleGrandMother.setPDG(300553);
1729 graphParticleMother.setPDG(-521);
1730 graphParticleAunt.setPDG(521);
1731 graphParticleDaughter1.setPDG(Const::electron.getPDGCode());
1732 graphParticleDaughter2.setPDG(-12);
1733
1734 graphParticleGrandMother.setMomentum(0.0, 0.0, 0.4);
1735 graphParticleMother.setMomentum(1.1, 1.3, 1.5);
1736
1737 graphParticleMother.comesFrom(graphParticleGrandMother);
1738 graphParticleAunt.comesFrom(graphParticleGrandMother);
1739 graphParticleDaughter1.comesFrom(graphParticleMother);
1740 graphParticleDaughter2.comesFrom(graphParticleMother);
1741
1742 mcGraph.generateList();
1743
1744 // Get MC Particles from StoreArray
1745 auto* mcGrandMother = mcParticles[0];
1746 mcGrandMother->setStatus(MCParticle::c_PrimaryParticle);
1747
1748 auto* mcMother = mcParticles[1];
1749 mcMother->setStatus(MCParticle::c_PrimaryParticle);
1750
1751 auto* mcAunt = mcParticles[2];
1752 mcAunt->setStatus(MCParticle::c_PrimaryParticle);
1753
1754 auto* mcDaughter1 = mcParticles[3];
1755 mcDaughter1->setStatus(MCParticle::c_PrimaryParticle);
1756
1757 auto* mcDaughter2 = mcParticles[4];
1758 mcDaughter2->setStatus(MCParticle::c_PrimaryParticle);
1759
1760 auto* p1 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
1761 p1->addRelationTo(mcDaughter1);
1762
1763 // For test of particle that has no MC match
1764 auto* p_noMC = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 211);
1765
1766 const Manager::Var* var = Manager::Instance().getVariable("genUpsilon4S(PDG)");
1767 ASSERT_NE(var, nullptr);
1768 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), 300553);
1769 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), 300553);
1770
1771 var = Manager::Instance().getVariable("genUpsilon4S(matchedMC(pz))");
1772 ASSERT_NE(var, nullptr);
1773 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), 0.4);
1774 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), 0.4);
1775
1776 var = Manager::Instance().getVariable("genUpsilon4S(mcDaughter(0, PDG))");
1777 ASSERT_NE(var, nullptr);
1778 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), -521);
1779 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), -521);
1780
1781 var = Manager::Instance().getVariable("genUpsilon4S(mcDaughter(0, matchedMC(px)))");
1782 ASSERT_NE(var, nullptr);
1783 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), 1.1);
1784 EXPECT_FLOAT_EQ(std::get<double>(var->function(p_noMC)), 1.1);
1785
1787 mcParticles.clear();
1788 particles.clear();
1789 MCParticleGraph mcGraph2;
1790
1791 MCParticleGraph::GraphParticle& graphParticle1 = mcGraph2.addParticle();
1792 MCParticleGraph::GraphParticle& graphParticle2 = mcGraph2.addParticle();
1793
1794 graphParticle1.setPDG(Const::electron.getPDGCode());
1795 graphParticle2.setPDG(-Const::electron.getPDGCode());
1796
1797 graphParticle1.setMomentum(1.1, 1.3, 1.4);
1798 graphParticle1.setMomentum(-1.1, -1.3, 1.4);
1799
1800 mcGraph2.generateList();
1801
1802 auto* mcP1 = mcParticles[0];
1803 mcP1->setStatus(MCParticle::c_PrimaryParticle);
1804
1805 auto* mcP2 = mcParticles[1];
1806 mcP2->setStatus(MCParticle::c_PrimaryParticle);
1807
1808 auto* someParticle = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
1809 someParticle->addRelationTo(mcP1);
1810
1811 var = Manager::Instance().getVariable("genUpsilon4S(PDG)");
1812 ASSERT_NE(var, nullptr);
1813 EXPECT_TRUE(std::isnan(std::get<double>(var->function(someParticle))));
1814 }
1815
1816 TEST_F(MetaVariableTest, daughterProductOf)
1817 {
1818 PxPyPzEVector momentum;
1819 const int nDaughters = 4;
1820 StoreArray<Particle> particles;
1821 std::vector<int> daughterIndices;
1822 for (int i = 0; i < nDaughters; i++) {
1823 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 2.0), (i % 2) ? 213 : -213);
1824 momentum += d.get4Vector();
1825 Particle* newDaughters = particles.appendNew(d);
1826 daughterIndices.push_back(newDaughters->getArrayIndex());
1827 }
1828 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1829
1830 const Manager::Var* var = Manager::Instance().getVariable("daughterProductOf(E)");
1831 ASSERT_NE(var, nullptr);
1832 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 120.0);
1833 }
1834
1835 TEST_F(MetaVariableTest, daughterSumOf)
1836 {
1837 PxPyPzEVector momentum;
1838 const int nDaughters = 4;
1839 StoreArray<Particle> particles;
1840 std::vector<int> daughterIndices;
1841 for (int i = 0; i < nDaughters; i++) {
1842 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 2.0), (i % 2) ? 213 : -213);
1843 momentum += d.get4Vector();
1844 Particle* newDaughters = particles.appendNew(d);
1845 daughterIndices.push_back(newDaughters->getArrayIndex());
1846 }
1847 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1848
1849 const Manager::Var* var = Manager::Instance().getVariable("daughterSumOf(E)");
1850 ASSERT_NE(var, nullptr);
1851 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 14.0);
1852 }
1853
1854 TEST_F(MetaVariableTest, daughterLowest)
1855 {
1856 PxPyPzEVector momentum;
1857 const int nDaughters = 4;
1858 StoreArray<Particle> particles;
1859 std::vector<int> daughterIndices;
1860 for (int i = 0; i < nDaughters; i++) {
1861 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 2.0), (i % 2) ? 213 : -213);
1862 momentum += d.get4Vector();
1863 Particle* newDaughters = particles.appendNew(d);
1864 daughterIndices.push_back(newDaughters->getArrayIndex());
1865 }
1866 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1867
1868 const Manager::Var* var = Manager::Instance().getVariable("daughterLowest(E)");
1869 ASSERT_NE(var, nullptr);
1870 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 2.0);
1871 }
1872
1873 TEST_F(MetaVariableTest, daughterHighest)
1874 {
1875 PxPyPzEVector momentum;
1876 const int nDaughters = 4;
1877 StoreArray<Particle> particles;
1878 std::vector<int> daughterIndices;
1879 for (int i = 0; i < nDaughters; i++) {
1880 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 1.0), (i % 2) ? 213 : -213);
1881 momentum += d.get4Vector();
1882 Particle* newDaughters = particles.appendNew(d);
1883 daughterIndices.push_back(newDaughters->getArrayIndex());
1884 }
1885 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1886
1887 const Manager::Var* var = Manager::Instance().getVariable("daughterHighest(E)");
1888 ASSERT_NE(var, nullptr);
1889 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 4.0);
1890 }
1891
1892 TEST_F(MetaVariableTest, daughterDiffOf)
1893 {
1894 PxPyPzEVector momentum;
1895 const int nDaughters = 4;
1896 StoreArray<Particle> particles;
1897 std::vector<int> daughterIndices;
1898 for (int i = 0; i < nDaughters; i++) {
1899 Particle d(PxPyPzEVector(-1, 1.0 - 2 * (i % 2), 1, i * 1.0 + 2.0), (i % 2) ? -11 : 211);
1900 momentum += d.get4Vector();
1901 Particle* newDaughters = particles.appendNew(d);
1902 daughterIndices.push_back(newDaughters->getArrayIndex());
1903 }
1904 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1905
1906 const Manager::Var* var = Manager::Instance().getVariable("daughterDiffOf(0, 1, PDG)");
1907 ASSERT_NE(var, nullptr);
1908 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -222);
1909
1910 var = Manager::Instance().getVariable("daughterDiffOf(1, 0, PDG)");
1911 ASSERT_NE(var, nullptr);
1912 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 222);
1913
1914 var = Manager::Instance().getVariable("daughterDiffOf(0, 1, abs(PDG))");
1915 ASSERT_NE(var, nullptr);
1916 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -200);
1917
1918 var = Manager::Instance().getVariable("daughterDiffOf(1, 1, PDG)");
1919 ASSERT_NE(var, nullptr);
1920 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0);
1921
1922 var = Manager::Instance().getVariable("daughterDiffOf(1, 3, abs(PDG))");
1923 ASSERT_NE(var, nullptr);
1924 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0);
1925
1926 var = Manager::Instance().getVariable("daughterDiffOf(0, 2, PDG)");
1927 ASSERT_NE(var, nullptr);
1928 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0);
1929
1930 var = Manager::Instance().getVariable("daughterDiffOf(1, 0, phi)");
1931 ASSERT_NE(var, nullptr);
1932 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -1.5707964);
1933
1934 var = Manager::Instance().getVariable("daughterDiffOf(1, 0, useCMSFrame(phi))");
1935 ASSERT_NE(var, nullptr);
1936 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -1.5004894);
1937
1938 var = Manager::Instance().getVariable("daughterDiffOf(0, NOTINT, PDG)");
1939 ASSERT_NE(var, nullptr);
1940 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
1941 }
1942
1943
1944 TEST_F(MetaVariableTest, mcDaughterDiffOf)
1945 {
1947 PxPyPzEVector momentum;
1948 const int nDaughters = 4;
1949 StoreArray<Particle> particles;
1950 StoreArray<MCParticle> mcParticles;
1951 particles.registerRelationTo(mcParticles);
1952 std::vector<int> daughterIndices;
1954
1955 for (int i = 0; i < nDaughters; i++) {
1956 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 1.0), (i % 2) ? -11 : 211);
1957 momentum += d.get4Vector();
1958 Particle* newDaughters = particles.appendNew(d);
1959 daughterIndices.push_back(newDaughters->getArrayIndex());
1960 auto* mcParticle = mcParticles.appendNew();
1961 mcParticle->setPDG((i % 2) ? -Const::electron.getPDGCode() : Const::pion.getPDGCode());
1963 newDaughters->addRelationTo(mcParticle);
1964 }
1965 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
1966
1967 const Manager::Var* var = Manager::Instance().getVariable("mcDaughterDiffOf(0, 1, PDG)");
1968 ASSERT_NE(var, nullptr);
1969 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -222);
1970
1971 var = Manager::Instance().getVariable("mcDaughterDiffOf(1, 0, PDG)");
1972 ASSERT_NE(var, nullptr);
1973 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 222);
1974
1975 var = Manager::Instance().getVariable("mcDaughterDiffOf(0, 1, abs(PDG))");
1976 ASSERT_NE(var, nullptr);
1977 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -200);
1978
1979 var = Manager::Instance().getVariable("mcDaughterDiffOf(1, 1, PDG)");
1980 ASSERT_NE(var, nullptr);
1981 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0);
1982
1983 var = Manager::Instance().getVariable("mcDaughterDiffOf(1, 3, abs(PDG))");
1984 ASSERT_NE(var, nullptr);
1985 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0);
1986
1987 var = Manager::Instance().getVariable("mcDaughterDiffOf(0, 2, PDG)");
1988 ASSERT_NE(var, nullptr);
1989 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0);
1990
1991 var = Manager::Instance().getVariable("mcDaughterDiffOf(0, NOTINT, PDG)");
1992 ASSERT_NE(var, nullptr);
1993 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
1994 }
1995
1996
1997
1998 TEST_F(MetaVariableTest, daughterClusterAngleInBetween)
1999 {
2000 // declare all the array we need
2001 StoreArray<Particle> particles;
2002 std::vector<int> daughterIndices, daughterIndices_noclst;
2003
2004 //proxy initialize where to declare the needed array
2006 StoreArray<ECLCluster> eclclusters;
2007 eclclusters.registerInDataStore();
2008 particles.registerRelationTo(eclclusters);
2010
2011 // create two Lorentz vectors that are back to back in the CMS and boost them to the Lab frame
2012 const float px_CM = 2.;
2013 const float py_CM = 1.;
2014 const float pz_CM = 3.;
2015 float E_CM;
2016 E_CM = sqrt(pow(px_CM, 2) + pow(py_CM, 2) + pow(pz_CM, 2));
2017 PxPyPzEVector momentum, momentum_noclst;
2018 PxPyPzEVector dau0_4vec_CM(px_CM, py_CM, pz_CM, E_CM), dau1_4vec_CM(-px_CM, -py_CM, -pz_CM, E_CM);
2019 PxPyPzEVector dau0_4vec_Lab, dau1_4vec_Lab;
2020 dau0_4vec_Lab = PCmsLabTransform::cmsToLab(
2021 dau0_4vec_CM); //why is everybody using the extended method when there are the functions that do all the steps for us?
2022 dau1_4vec_Lab = PCmsLabTransform::cmsToLab(dau1_4vec_CM);
2023
2024 // add the two photons (now in the Lab frame) as the two daughters of some particle and create the latter
2025 Particle dau0_noclst(dau0_4vec_Lab, 22);
2026 momentum += dau0_noclst.get4Vector();
2027 Particle* newDaughter0_noclst = particles.appendNew(dau0_noclst);
2028 daughterIndices_noclst.push_back(newDaughter0_noclst->getArrayIndex());
2029 Particle dau1_noclst(dau1_4vec_Lab, 22);
2030 momentum += dau1_noclst.get4Vector();
2031 Particle* newDaughter1_noclst = particles.appendNew(dau1_noclst);
2032 daughterIndices_noclst.push_back(newDaughter1_noclst->getArrayIndex());
2033 const Particle* par_noclst = particles.appendNew(momentum, 111, Particle::c_Unflavored, daughterIndices_noclst);
2034
2035 // grab variables
2036 const Manager::Var* var = Manager::Instance().getVariable("daughterClusterAngleInBetween(0, 1)");
2037 const Manager::Var* varCMS = Manager::Instance().getVariable("useCMSFrame(daughterClusterAngleInBetween(0, 1))");
2038
2039 // when no relations are set between the particles and the eclClusters, nan is expected to be returned
2040 ASSERT_NE(var, nullptr);
2041 EXPECT_TRUE(std::isnan(std::get<double>(var->function(par_noclst))));
2042
2043 // set relations between particles and eclClusters
2044 ECLCluster* eclst0 = eclclusters.appendNew(ECLCluster());
2045 eclst0->setEnergy(dau0_4vec_Lab.E());
2046 eclst0->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
2047 eclst0->setClusterId(1);
2048 eclst0->setTheta(dau0_4vec_Lab.Theta());
2049 eclst0->setPhi(dau0_4vec_Lab.Phi());
2050 eclst0->setR(148.4);
2051 ECLCluster* eclst1 = eclclusters.appendNew(ECLCluster());
2052 eclst1->setEnergy(dau1_4vec_Lab.E());
2053 eclst1->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
2054 eclst1->setClusterId(2);
2055 eclst1->setTheta(dau1_4vec_Lab.Theta());
2056 eclst1->setPhi(dau1_4vec_Lab.Phi());
2057 eclst1->setR(148.5);
2058
2059 const Particle* newDaughter0 = particles.appendNew(Particle(eclclusters[0]));
2060 daughterIndices.push_back(newDaughter0->getArrayIndex());
2061 const Particle* newDaughter1 = particles.appendNew(Particle(eclclusters[1]));
2062 daughterIndices.push_back(newDaughter1->getArrayIndex());
2063
2064 const Particle* par = particles.appendNew(momentum, 111, Particle::c_Unflavored, daughterIndices);
2065
2066 //now we expect non-nan results
2067 EXPECT_FLOAT_EQ(std::get<double>(var->function(par)), 2.8613892);
2068 EXPECT_FLOAT_EQ(std::get<double>(varCMS->function(par)), M_PI);
2069 }
2070
2071 TEST_F(MetaVariableTest, grandDaughterDiffOfs)
2072 {
2073 // declare all the array we need
2074 StoreArray<Particle> particles;
2075 std::vector<int> daughterIndices0_noclst, daughterIndices1_noclst, daughterIndices2_noclst;
2076 std::vector<int> daughterIndices0, daughterIndices1, daughterIndices2;
2077
2078 //proxy initialize where to declare the needed array
2080 StoreArray<ECLCluster> eclclusters;
2081 eclclusters.registerInDataStore();
2082 particles.registerRelationTo(eclclusters);
2084
2085 // create two Lorentz vectors
2086 const float px_0 = 2.;
2087 const float py_0 = 1.;
2088 const float pz_0 = 3.;
2089 const float px_1 = 1.5;
2090 const float py_1 = 1.5;
2091 const float pz_1 = 2.5;
2092 float E_0, E_1;
2093 E_0 = sqrt(pow(px_0, 2) + pow(py_0, 2) + pow(pz_0, 2));
2094 E_1 = sqrt(pow(px_1, 2) + pow(py_1, 2) + pow(pz_1, 2));
2095 PxPyPzEVector momentum_0, momentum_1, momentum;
2096 PxPyPzEVector dau0_4vec(px_0, py_0, pz_0, E_0), dau1_4vec(px_1, py_1, pz_1, E_1);
2097
2098 // add the two photons as the two daughters of some particle and create the latter
2099 // Particle dau0_noclst(dau0_4vec, 22);
2100 // momentum += dau0_noclst.get4Vector();
2101 // Particle* newDaughter0_noclst = particles.appendNew(dau0_noclst);
2102 // daughterIndices_noclst.push_back(newDaughter0_noclst->getArrayIndex());
2103 // Particle dau1_noclst(dau1_4vec, 22);
2104 // momentum += dau1_noclst.get4Vector();
2105 // Particle* newDaughter1_noclst = particles.appendNew(dau1_noclst);
2106 // daughterIndices_noclst.push_back(newDaughter1_noclst->getArrayIndex());
2107 // const Particle* par_noclst = particles.appendNew(momentum, 111, Particle::c_Unflavored, daughterIndices_noclst);
2108
2109 Particle dau0_noclst(dau0_4vec, 22);
2110 momentum_0 = dau0_4vec;
2111 Particle* newDaughter0_noclst = particles.appendNew(dau0_noclst);
2112 daughterIndices0_noclst.push_back(newDaughter0_noclst->getArrayIndex());
2113 const Particle* par0_noclst = particles.appendNew(momentum_0, 111, Particle::c_Unflavored, daughterIndices0_noclst);
2114 Particle dau1_noclst(dau1_4vec, 22);
2115 momentum_1 = dau1_4vec;
2116 Particle* newDaughter1_noclst = particles.appendNew(dau1_noclst);
2117 daughterIndices1_noclst.push_back(newDaughter1_noclst->getArrayIndex());
2118 const Particle* par1_noclst = particles.appendNew(momentum_1, 111, Particle::c_Unflavored, daughterIndices1_noclst);
2119
2120 momentum = momentum_0 + momentum_1;
2121 daughterIndices2_noclst.push_back(par0_noclst->getArrayIndex());
2122 daughterIndices2_noclst.push_back(par1_noclst->getArrayIndex());
2123 const Particle* parGranny_noclst = particles.appendNew(momentum, 111, Particle::c_Unflavored, daughterIndices2_noclst);
2124
2125 // grab variables
2126 const Manager::Var* var_Theta = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,0,0,theta)");
2127 const Manager::Var* var_ClusterTheta = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,0,0,clusterTheta)");
2128 const Manager::Var* var_E = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,0,0,E)");
2129 const Manager::Var* var_ClusterE = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,0,0,clusterE)");
2130 const Manager::Var* var_E_wrongIndexes = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,2,3,E)");
2131 const Manager::Var* var_ClusterE_wrongIndexes = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,2,3,clusterE)");
2132
2133 const Manager::Var* var_ClusterPhi = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,0,0,clusterPhi)");
2134 const Manager::Var* var_Phi = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,0,0,phi)");
2135 const Manager::Var* var_ClusterPhi_wrongIndexes = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,2,3,clusterPhi)");
2136 const Manager::Var* var_Phi_wrongIndexes = Manager::Instance().getVariable("grandDaughterDiffOf(0,1,2,3,phi)");
2137
2138 // when no relations are set between the particles and the eclClusters, nan is expected to be returned for the Cluster- vars
2139 // no problems are supposed to happen for non-Cluster- vars
2140 // also, we expect NaN when we pass wrong indexes
2141 ASSERT_NE(var_ClusterPhi, nullptr);
2142 EXPECT_TRUE(std::isnan(std::get<double>(var_ClusterPhi->function(parGranny_noclst))));
2143 EXPECT_TRUE(std::isnan(std::get<double>(var_ClusterTheta->function(parGranny_noclst))));
2144 EXPECT_TRUE(std::isnan(std::get<double>(var_ClusterE->function(parGranny_noclst))));
2145 EXPECT_FLOAT_EQ(std::get<double>(var_Phi->function(parGranny_noclst)), 0.32175055);
2146 EXPECT_FLOAT_EQ(std::get<double>(var_Theta->function(parGranny_noclst)), 0.06311664);
2147 EXPECT_FLOAT_EQ(std::get<double>(var_E->function(parGranny_noclst)), -0.46293807);
2148 EXPECT_TRUE(std::isnan(std::get<double>(var_ClusterPhi_wrongIndexes->function(parGranny_noclst))));
2149 EXPECT_TRUE(std::isnan(std::get<double>(var_Phi_wrongIndexes->function(parGranny_noclst))));
2150 EXPECT_TRUE(std::isnan(std::get<double>(var_ClusterE_wrongIndexes->function(parGranny_noclst))));
2151 EXPECT_TRUE(std::isnan(std::get<double>(var_E_wrongIndexes->function(parGranny_noclst))));
2152
2153 // set relations between particles and eclClusters
2154 ECLCluster* eclst0 = eclclusters.appendNew(ECLCluster());
2155 eclst0->setEnergy(dau0_4vec.E());
2156 eclst0->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
2157 eclst0->setClusterId(1);
2158 eclst0->setTheta(dau0_4vec.Theta());
2159 eclst0->setPhi(dau0_4vec.Phi());
2160 eclst0->setR(148.4);
2161 ECLCluster* eclst1 = eclclusters.appendNew(ECLCluster());
2162 eclst1->setEnergy(dau1_4vec.E());
2163 eclst1->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
2164 eclst1->setClusterId(2);
2165 eclst1->setTheta(dau1_4vec.Theta());
2166 eclst1->setPhi(dau1_4vec.Phi());
2167 eclst1->setR(148.5);
2168
2169 const Particle* newDaughter0 = particles.appendNew(Particle(eclclusters[0]));
2170 daughterIndices0.push_back(newDaughter0->getArrayIndex());
2171 const Particle* par0 = particles.appendNew(momentum_0, 111, Particle::c_Unflavored, daughterIndices0);
2172
2173 const Particle* newDaughter1 = particles.appendNew(Particle(eclclusters[1]));
2174 daughterIndices1.push_back(newDaughter1->getArrayIndex());
2175 const Particle* par1 = particles.appendNew(momentum_1, 111, Particle::c_Unflavored, daughterIndices1);
2176
2177 daughterIndices2.push_back(par0->getArrayIndex());
2178 daughterIndices2.push_back(par1->getArrayIndex());
2179 const Particle* parGranny = particles.appendNew(momentum, 111, Particle::c_Unflavored, daughterIndices2);
2180 //const Particle* par = particles.appendNew(momentum, 111, Particle::c_Unflavored, daughterIndices);
2181
2182 //now we expect non-nan results
2183 EXPECT_FLOAT_EQ(std::get<double>(var_ClusterPhi->function(parGranny)), 0.32175055);
2184 EXPECT_FLOAT_EQ(std::get<double>(var_Phi->function(parGranny)), 0.32175055);
2185 EXPECT_FLOAT_EQ(std::get<double>(var_ClusterTheta->function(parGranny)), 0.06311664);
2186 EXPECT_FLOAT_EQ(std::get<double>(var_Theta->function(parGranny)), 0.06311664);
2187 EXPECT_FLOAT_EQ(std::get<double>(var_ClusterE->function(parGranny)), -0.46293831);
2188 EXPECT_FLOAT_EQ(std::get<double>(var_E->function(parGranny)), -0.46293831);
2189 }
2190
2191 TEST_F(MetaVariableTest, daughterNormDiffOf)
2192 {
2193 PxPyPzEVector momentum;
2194 const int nDaughters = 4;
2195 StoreArray<Particle> particles;
2196 std::vector<int> daughterIndices;
2197 for (int i = 0; i < nDaughters; i++) {
2198 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 1.0), (i % 2) ? -11 : 211);
2199 momentum += d.get4Vector();
2200 Particle* newDaughters = particles.appendNew(d);
2201 daughterIndices.push_back(newDaughters->getArrayIndex());
2202 }
2203 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
2204
2205 const Manager::Var* var = Manager::Instance().getVariable("daughterNormDiffOf(0, 1, PDG)");
2206 ASSERT_NE(var, nullptr);
2207 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -222 / 200.);
2208
2209 var = Manager::Instance().getVariable("daughterNormDiffOf(1, 0, PDG)");
2210 ASSERT_NE(var, nullptr);
2211 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 222 / 200.);
2212
2213 var = Manager::Instance().getVariable("daughterNormDiffOf(0, 1, abs(PDG))");
2214 ASSERT_NE(var, nullptr);
2215 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -200 / 222.);
2216
2217 var = Manager::Instance().getVariable("daughterNormDiffOf(1, 1, PDG)");
2218 ASSERT_NE(var, nullptr);
2219 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), -0 / 22.);
2220
2221 var = Manager::Instance().getVariable("daughterNormDiffOf(1, 3, abs(PDG))");
2222 ASSERT_NE(var, nullptr);
2223 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0 / 22.);
2224
2225 var = Manager::Instance().getVariable("daughterNormDiffOf(0, 2, PDG)");
2226 ASSERT_NE(var, nullptr);
2227 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0 / 422.);
2228
2229 }
2230
2231 TEST_F(MetaVariableTest, daughterMotherDiffOf)
2232 {
2233 PxPyPzEVector momentum;
2234 const int nDaughters = 4;
2235 StoreArray<Particle> particles;
2236 std::vector<int> daughterIndices;
2237 for (int i = 0; i < nDaughters; i++) {
2238 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 1.0), (i % 2) ? -11 : 211);
2239 momentum += d.get4Vector();
2240 Particle* newDaughters = particles.appendNew(d);
2241 daughterIndices.push_back(newDaughters->getArrayIndex());
2242 }
2243 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
2244
2245 const Manager::Var* var = Manager::Instance().getVariable("daughterMotherDiffOf(1, PDG)");
2246 ASSERT_NE(var, nullptr);
2247 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 422);
2248
2249 var = Manager::Instance().getVariable("daughterMotherDiffOf(1, abs(PDG))");
2250 ASSERT_NE(var, nullptr);
2251 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 400);
2252
2253 var = Manager::Instance().getVariable("daughterMotherDiffOf(0, PDG)");
2254 ASSERT_NE(var, nullptr);
2255 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 200);
2256
2257 }
2258
2259 TEST_F(MetaVariableTest, daughterMotherNormDiffOf)
2260 {
2261 PxPyPzEVector momentum;
2262 const int nDaughters = 4;
2263 StoreArray<Particle> particles;
2264 std::vector<int> daughterIndices;
2265 for (int i = 0; i < nDaughters; i++) {
2266 Particle d(PxPyPzEVector(1, 1, 1, i * 1.0 + 1.0), (i % 2) ? -11 : 211);
2267 momentum += d.get4Vector();
2268 Particle* newDaughters = particles.appendNew(d);
2269 daughterIndices.push_back(newDaughters->getArrayIndex());
2270 }
2271 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Unflavored, daughterIndices);
2272
2273 const Manager::Var* var = Manager::Instance().getVariable("daughterMotherNormDiffOf(1, PDG)");
2274 ASSERT_NE(var, nullptr);
2275 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 422 / 400.);
2276
2277 var = Manager::Instance().getVariable("daughterMotherNormDiffOf(1, abs(PDG))");
2278 ASSERT_NE(var, nullptr);
2279 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 400 / 422.);
2280
2281 var = Manager::Instance().getVariable("daughterMotherNormDiffOf(0, PDG)");
2282 ASSERT_NE(var, nullptr);
2283 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 200 / 622.);
2284
2285 }
2286
2287 TEST_F(MetaVariableTest, constant)
2288 {
2289
2290 const Manager::Var* var = Manager::Instance().getVariable("constant(1)");
2291 ASSERT_NE(var, nullptr);
2292 EXPECT_FLOAT_EQ(std::get<double>(var->function(nullptr)), 1.0);
2293
2294 var = Manager::Instance().getVariable("constant(0)");
2295 ASSERT_NE(var, nullptr);
2296 EXPECT_FLOAT_EQ(std::get<double>(var->function(nullptr)), 0.0);
2297
2298 }
2299
2300 TEST_F(MetaVariableTest, abs)
2301 {
2302 Particle p({ 0.1, -0.4, 0.8, 2.0 }, 11);
2303 Particle p2({ -0.1, -0.4, 0.8, 4.0 }, -11);
2304
2305 const Manager::Var* var = Manager::Instance().getVariable("abs(px)");
2306 ASSERT_NE(var, nullptr);
2307 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 0.1);
2308 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p2)), 0.1);
2309
2310 }
2311
2312 TEST_F(MetaVariableTest, sin)
2313 {
2314 Particle p({ 3.14159265359 / 2.0, -0.4, 0.8, 1.0}, 11);
2315 Particle p2({ 0.0, -0.4, 0.8, 1.0 }, -11);
2316
2317 const Manager::Var* var = Manager::Instance().getVariable("sin(px)");
2318 ASSERT_NE(var, nullptr);
2319 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p)), 1.0);
2320 EXPECT_NEAR(std::get<double>(var->function(&p2)), 0.0, 1e-6);
2321
2322 }
2323
2324 TEST_F(MetaVariableTest, cos)
2325 {
2326 Particle p({ 3.14159265359 / 2.0, -0.4, 0.8, 1.0}, 11);
2327 Particle p2({ 0.0, -0.4, 0.8, 1.0 }, -11);
2328
2329 const Manager::Var* var = Manager::Instance().getVariable("cos(px)");
2330 ASSERT_NE(var, nullptr);
2331 EXPECT_NEAR(std::get<double>(var->function(&p)), 0.0, 1e-6);
2332 EXPECT_FLOAT_EQ(std::get<double>(var->function(&p2)), 1.0);
2333
2334 }
2335
2336 TEST_F(MetaVariableTest, NBDeltaIfMissingDeathTest)
2337 {
2338 //Variable got removed, test for absence
2339 EXPECT_B2FATAL(Manager::Instance().getVariable("NBDeltaIfMissing(TOP, 11)"));
2340 EXPECT_B2FATAL(Manager::Instance().getVariable("NBDeltaIfMissing(ARICH, 11)"));
2341 }
2342
2343 TEST_F(MetaVariableTest, matchedMC)
2344 {
2346 StoreArray<MCParticle> mcParticles;
2347 StoreArray<Particle> particles;
2348 particles.registerRelationTo(mcParticles);
2350
2351 auto* mcParticle = mcParticles.appendNew();
2352 mcParticle->setPDG(Const::electron.getPDGCode());
2354 auto* p1 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
2355 p1->addRelationTo(mcParticle);
2356
2357 mcParticle = mcParticles.appendNew();
2358 mcParticle->setPDG(-Const::electron.getPDGCode());
2360 auto* p2 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
2361 p2->addRelationTo(mcParticle);
2362
2363 mcParticle = mcParticles.appendNew();
2364 mcParticle->setPDG(Const::photon.getPDGCode());
2366 auto* p3 = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 11);
2367 p3->addRelationTo(mcParticle);
2368
2369 // Test if matchedMC also works for particle which already is an MCParticle.
2370 auto* p4 = particles.appendNew(mcParticle);
2371
2372 const Manager::Var* var = Manager::Instance().getVariable("matchedMC(charge)");
2373 ASSERT_NE(var, nullptr);
2374 EXPECT_FLOAT_EQ(std::get<double>(var->function(p1)), -1);
2375 EXPECT_FLOAT_EQ(std::get<double>(var->function(p2)), 1);
2376 EXPECT_FLOAT_EQ(std::get<double>(var->function(p3)), 0);
2377 EXPECT_FLOAT_EQ(std::get<double>(var->function(p4)), 0);
2378 }
2379
2380 TEST_F(MetaVariableTest, countInList)
2381 {
2382 StoreArray<Particle> particles;
2384
2385 StoreObjPtr<ParticleList> outputList("pList1");
2387 outputList.registerInDataStore(flags);
2389 outputList.create();
2390 outputList->initialize(22, "pList1");
2391
2392 particles.appendNew(Particle({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2));
2393 particles.appendNew(Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3));
2394 particles.appendNew(Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4));
2395 particles.appendNew(Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 5));
2396 particles.appendNew(Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 6));
2397
2398 outputList->addParticle(0, 22, Particle::c_Unflavored);
2399 outputList->addParticle(1, 22, Particle::c_Unflavored);
2400 outputList->addParticle(2, 22, Particle::c_Unflavored);
2401 outputList->addParticle(3, 22, Particle::c_Unflavored);
2402 outputList->addParticle(4, 22, Particle::c_Unflavored);
2403
2404 const Manager::Var* var = Manager::Instance().getVariable("countInList(pList1, E < 0.85)");
2405 ASSERT_NE(var, nullptr);
2406 EXPECT_EQ(std::get<int>(var->function(nullptr)), 2);
2407
2408 var = Manager::Instance().getVariable("countInList(pList1)");
2409 ASSERT_NE(var, nullptr);
2410 EXPECT_EQ(std::get<int>(var->function(nullptr)), 5);
2411
2412 var = Manager::Instance().getVariable("countInList(pList1, E > 5)");
2413 ASSERT_NE(var, nullptr);
2414 EXPECT_EQ(std::get<int>(var->function(nullptr)), 0);
2415
2416 var = Manager::Instance().getVariable("countInList(pList1, E < 5)");
2417 ASSERT_NE(var, nullptr);
2418 EXPECT_EQ(std::get<int>(var->function(nullptr)), 5);
2419 }
2420
2421 TEST_F(MetaVariableTest, isInList)
2422 {
2423 // we need the particles StoreArray
2424 StoreArray<Particle> particles;
2426
2427 // create a photon list for testing
2428 StoreObjPtr<ParticleList> gammalist("testGammaList");
2430 gammalist.registerInDataStore(flags);
2432 gammalist.create();
2433 gammalist->initialize(22, "testGammaList");
2434
2435 // mock up two photons
2436 Particle goingin({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0);
2437 Particle notgoingin({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1);
2438 auto* inthelist = particles.appendNew(goingin);
2439 auto* notinthelist = particles.appendNew(notgoingin);
2440
2441 // put the the zeroth one in the list the first on not in the list
2442 gammalist->addParticle(0, 22, Particle::c_Unflavored);
2443
2444 // get the variables
2445 const Manager::Var* vnonsense = Manager::Instance().getVariable("isInList(NONEXISTANTLIST)");
2446 const Manager::Var* vsensible = Manager::Instance().getVariable("isInList(testGammaList)");
2447
2448 // -
2449 EXPECT_B2FATAL(std::get<bool>(vnonsense->function(notinthelist)));
2450 EXPECT_TRUE(std::get<bool>(vsensible->function(inthelist)));
2451 EXPECT_FALSE(std::get<bool>(vsensible->function(notinthelist)));
2452 }
2453
2455 TEST_F(MetaVariableTest, cutIsInList)
2456 {
2457 StoreArray<Particle> particles;
2459
2460 // create a photon list for testing
2461 const std::string listname {"wil/d(-+)'':l*"};
2462
2463 StoreObjPtr<ParticleList> particlelist(listname);
2465 particlelist.registerInDataStore(flags);
2467 particlelist.create();
2468 particlelist->initialize(22, listname);
2469
2470 Particle goingin({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0);
2471 Particle notgoingin({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1);
2472 auto* inthelist = particles.appendNew(goingin);
2473 auto* notinthelist = particles.appendNew(notgoingin);
2474
2475 // put the the zeroth one in the list the first on not in the list
2476 particlelist->addParticle(0, 22, Particle::c_Unflavored);
2477
2478 // use passesCut metavariable to check cut parsing of isInList particle list.
2479 const Manager::Var* nonexistlist = Manager::Instance().getVariable("passesCut(isInList(NONEXISTANTLIST))");
2480 const Manager::Var* existlist = Manager::Instance().getVariable("passesCut(isInList(" + listname + "))");
2481
2482 EXPECT_B2FATAL(std::get<bool>(nonexistlist->function(inthelist)));
2483 EXPECT_FALSE(std::get<bool>(existlist->function(notinthelist)));
2484 EXPECT_TRUE(std::get<bool>(existlist->function(inthelist)));
2485 }
2486
2487 TEST_F(MetaVariableTest, sourceObjectIsInList)
2488 {
2489 // datastore things
2492
2493 // needed to mock up
2494 StoreArray<ECLCluster> clusters;
2495 StoreArray<Particle> particles;
2496 StoreObjPtr<ParticleList> gammalist("testGammaList");
2497
2498 clusters.registerInDataStore();
2499 particles.registerInDataStore();
2501 gammalist.registerInDataStore(flags);
2502
2503 // end datastore things
2505
2506 // of course we have to create the list...
2507 gammalist.create();
2508 gammalist->initialize(22, "testGammaList");
2509
2510 // mock up two clusters from the ECL let's say they both came from true Klongs
2511 // but one looked a little bit photon-like
2512 auto* cl0 = clusters.appendNew(ECLCluster());
2513 cl0->setEnergy(1.0);
2514 cl0->setHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
2515 cl0->addHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron);
2516 cl0->setClusterId(0);
2517 auto* cl1 = clusters.appendNew(ECLCluster());
2518 cl1->setEnergy(1.0);
2519 cl1->setHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron);
2520 cl1->setClusterId(1);
2521
2522 // create particles from the clusters
2523 Particle myphoton(cl0, Const::photon);
2524 Particle iscopiedin(cl0, Const::Klong);
2525 Particle notcopiedin(cl1, Const::Klong);
2526
2527 // add the particle created from cluster zero to the gamma list
2528 auto* myphoton_ = particles.appendNew(myphoton);
2529 gammalist->addParticle(myphoton_);
2530
2531 auto* iscopied = particles.appendNew(iscopiedin); // a clone of this guy is now in the gamma list
2532 auto* notcopied = particles.appendNew(notcopiedin);
2533
2534 // get the variables
2535 const Manager::Var* vnonsense = Manager::Instance().getVariable("sourceObjectIsInList(NONEXISTANTLIST)");
2536 const Manager::Var* vsensible = Manager::Instance().getVariable("sourceObjectIsInList(testGammaList)");
2537
2538 // -
2539 EXPECT_B2FATAL(std::get<int>(vnonsense->function(iscopied)));
2540 EXPECT_EQ(std::get<int>(vsensible->function(iscopied)), 1);
2541 EXPECT_EQ(std::get<int>(vsensible->function(notcopied)), 0);
2542
2543 // now mock up some other type particles
2544 Particle composite({0.5, 0.4, 0.5, 0.8}, 512, Particle::c_Unflavored, Particle::c_Composite, 0);
2545 Particle undefined({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1);
2546 auto* composite_ = particles.appendNew(undefined);
2547 auto* undefined_ = particles.appendNew(composite);
2548 EXPECT_EQ(std::get<int>(vsensible->function(composite_)), -1);
2549 EXPECT_EQ(std::get<int>(vsensible->function(undefined_)), -1);
2550 }
2551
2552 TEST_F(MetaVariableTest, mcParticleIsInMCList)
2553 {
2554 // datastore things
2557
2558 // needed to mock up
2559 StoreArray<MCParticle> mcparticles;
2560 StoreArray<Particle> particles;
2561 StoreObjPtr<ParticleList> list("testList");
2562 StoreObjPtr<ParticleList> anotherlist("supplimentaryList");
2563
2564 mcparticles.registerInDataStore();
2565 particles.registerInDataStore();
2566 particles.registerRelationTo(mcparticles);
2568 list.registerInDataStore(flags);
2569 anotherlist.registerInDataStore(flags);
2570
2572 // end datastore setup
2573
2574 list.create();
2575 list->initialize(22, "testList");
2576
2577 anotherlist.create();
2578 anotherlist->initialize(22, "supplimentaryList");
2579
2580 // MCParticles
2581 auto* mcphoton = mcparticles.appendNew();
2582 mcphoton->setPDG(Const::photon.getPDGCode());
2583 mcphoton->setStatus(MCParticle::c_PrimaryParticle);
2584
2585 auto* mcelectron = mcparticles.appendNew();
2586 mcelectron->setPDG(Const::electron.getPDGCode());
2587 mcelectron->setStatus(MCParticle::c_PrimaryParticle);
2588
2589 auto* mcanotherelectron = mcparticles.appendNew();
2590 mcanotherelectron->setPDG(Const::photon.getPDGCode());
2591 mcanotherelectron->setStatus(MCParticle::c_PrimaryParticle);
2592
2593 auto* mcyetanotherelectron = mcparticles.appendNew();
2594 mcyetanotherelectron->setPDG(Const::photon.getPDGCode());
2595 mcyetanotherelectron->setStatus(MCParticle::c_PrimaryParticle);
2596
2597 // particles
2598 auto* photon = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 22);
2599 photon->addRelationTo(mcphoton);
2600 list->addParticle(photon);
2601
2602 auto* electron = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 22);
2603 electron->addRelationTo(mcelectron);
2604 list->addParticle(electron);
2605
2606 auto* other = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 22);
2607 other->addRelationTo(mcanotherelectron);
2608
2609 auto* yetanotherelectron = particles.appendNew(PxPyPzEVector({ 0.0, -0.4, 0.8, 1.0}), 22);
2610 yetanotherelectron->addRelationTo(mcyetanotherelectron);
2611 anotherlist->addParticle(yetanotherelectron);
2612 // not in the list
2613
2614 // get the variable
2615 const Manager::Var* vnonsense = Manager::Instance().getVariable("mcParticleIsInMCList(NONEXISTANTLIST)");
2616 const Manager::Var* vsensible = Manager::Instance().getVariable("mcParticleIsInMCList(testList)");
2617
2618 // -
2619 EXPECT_B2FATAL(std::get<bool>(vnonsense->function(photon)));
2620 EXPECT_TRUE(std::get<bool>(vsensible->function(photon)));
2621 EXPECT_TRUE(std::get<bool>(vsensible->function(electron)));
2622 EXPECT_FALSE(std::get<bool>(vsensible->function(other)));
2623 EXPECT_FALSE(std::get<bool>(vsensible->function(yetanotherelectron)));
2624
2625 // now mock up some other type particles
2626 Particle composite({0.5, 0.4, 0.5, 0.8}, 512, Particle::c_Unflavored, Particle::c_Composite, 0);
2627 Particle undefined({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1);
2628 auto* composite_ = particles.appendNew(undefined);
2629 auto* undefined_ = particles.appendNew(composite);
2630 EXPECT_FALSE(std::get<bool>(vsensible->function(composite_)));
2631 EXPECT_FALSE(std::get<bool>(vsensible->function(undefined_)));
2632 }
2633
2634 TEST_F(MetaVariableTest, mostB2BAndClosestParticles)
2635 {
2636 /* Mock up an event with a "photon" and an "electron" which are nearly back to
2637 * back, and second "photon" which is close-ish to the "electron".
2638 *
2639 * Other test of non-existent / empty lists and variables also included.
2640 */
2641
2642 // Connect gearbox for CMS variables
2643 Gearbox& gearbox = Gearbox::getInstance();
2644 gearbox.setBackends({std::string("file:")});
2645 gearbox.close();
2646 gearbox.open("geometry/Belle2.xml", false);
2647
2648 // we need the particles StoreArray
2649 StoreArray<Particle> particles;
2651
2652 // create a photon list for testing
2653 StoreObjPtr<ParticleList> gammalist("testGammaList");
2654 StoreObjPtr<ParticleList> emptylist("testEmptyList");
2656 gammalist.registerInDataStore(flags);
2657 emptylist.registerInDataStore(flags);
2659 gammalist.create();
2660 gammalist->initialize(22, "testGammaList");
2661 emptylist.create();
2662 emptylist->initialize(22, "testEmptyList");
2663
2664 // create some photons in an stdvector
2665 std::vector<Particle> gammavector = {
2666 Particle({ -1.0, -1.0, 0.8, 1.7}, // this should be the most b2b to our reference particle
2667 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
2668 Particle({0.2, 0.7, 0.9, 3.4}, // should be the closest
2669 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
2670 };
2671 // put the photons in the StoreArray
2672 for (const auto& g : gammavector)
2673 particles.appendNew(g);
2674
2675 // put the photons in the test list
2676 for (size_t i = 0; i < gammavector.size(); i++)
2677 gammalist->addParticle(i, 22, Particle::c_Unflavored);
2678
2679 // add the reference particle (electron) to the StoreArray
2680 const auto* electron = particles.appendNew(
2681 Particle({1.0, 1.0, 0.5, 1.6}, // somewhere in the +ve quarter of the detector
2682 11, Particle::c_Unflavored, Particle::c_Undefined, 2) // needs to be incremented if we add to gamma vector
2683 );
2684
2685 {
2686 EXPECT_B2FATAL(Manager::Instance().getVariable("angleToClosestInList"));
2687 EXPECT_B2FATAL(Manager::Instance().getVariable("angleToClosestInList(A, B)"));
2688
2689 const auto* nonexistent = Manager::Instance().getVariable("angleToClosestInList(NONEXISTANTLIST)");
2690 EXPECT_B2FATAL(std::get<double>(nonexistent->function(electron)));
2691
2692 const auto* empty = Manager::Instance().getVariable("angleToClosestInList(testEmptyList)");
2693 EXPECT_TRUE(std::isnan(std::get<double>(empty->function(electron))));
2694
2695 const auto* closest = Manager::Instance().getVariable("angleToClosestInList(testGammaList)");
2696 EXPECT_FLOAT_EQ(std::get<double>(closest->function(electron)), 0.68014491);
2697
2698 const auto* closestCMS = Manager::Instance().getVariable("useCMSFrame(angleToClosestInList(testGammaList))");
2699 EXPECT_FLOAT_EQ(std::get<double>(closestCMS->function(electron)), 0.67901474);
2700 }
2701
2702 {
2703 EXPECT_B2FATAL(Manager::Instance().getVariable("closestInList"));
2704 EXPECT_B2FATAL(Manager::Instance().getVariable("closestInList(A, B, C)"));
2705
2706 const auto* nonexistent = Manager::Instance().getVariable("closestInList(NONEXISTANTLIST, E)");
2707 EXPECT_B2FATAL(std::get<double>(nonexistent->function(electron)));
2708
2709 const auto* empty = Manager::Instance().getVariable("closestInList(testEmptyList, E)");
2710 EXPECT_TRUE(std::isnan(std::get<double>(empty->function(electron))));
2711
2712 const auto* closest = Manager::Instance().getVariable("closestInList(testGammaList, E)");
2713 EXPECT_FLOAT_EQ(std::get<double>(closest->function(electron)), 3.4);
2714
2715 const auto* closestCMS = Manager::Instance().getVariable("useCMSFrame(closestInList(testGammaList, E))");
2716 EXPECT_FLOAT_EQ(std::get<double>(closestCMS->function(electron)), 3.2732551); // the energy gets smeared because of boost
2717
2718 const auto* closestCMSLabE = Manager::Instance().getVariable("useCMSFrame(closestInList(testGammaList, useLabFrame(E)))");
2719 EXPECT_FLOAT_EQ(std::get<double>(closestCMSLabE->function(electron)), 3.4); // aaand should be back to the lab frame value
2720 }
2721
2722 {
2723 EXPECT_B2FATAL(Manager::Instance().getVariable("angleToMostB2BInList"));
2724 EXPECT_B2FATAL(Manager::Instance().getVariable("angleToMostB2BInList(A, B)"));
2725
2726 const auto* nonexistent = Manager::Instance().getVariable("angleToMostB2BInList(NONEXISTANTLIST)");
2727 EXPECT_B2FATAL(std::get<double>(nonexistent->function(electron)));
2728
2729 const auto* empty = Manager::Instance().getVariable("angleToMostB2BInList(testEmptyList)");
2730 EXPECT_TRUE(std::isnan(std::get<double>(empty->function(electron))));
2731
2732 const auto* mostB2B = Manager::Instance().getVariable("angleToMostB2BInList(testGammaList)");
2733 EXPECT_FLOAT_EQ(std::get<double>(mostB2B->function(electron)), 2.2869499);
2734
2735 const auto* mostB2BCMS = Manager::Instance().getVariable("useCMSFrame(angleToMostB2BInList(testGammaList))");
2736 EXPECT_FLOAT_EQ(std::get<double>(mostB2BCMS->function(electron)), 2.8312778);
2737 }
2738
2739 {
2740 EXPECT_B2FATAL(Manager::Instance().getVariable("mostB2BInList"));
2741 EXPECT_B2FATAL(Manager::Instance().getVariable("mostB2BInList(A, B, C)"));
2742
2743 const auto* nonexistent = Manager::Instance().getVariable("mostB2BInList(NONEXISTANTLIST, E)");
2744 EXPECT_B2FATAL(std::get<double>(nonexistent->function(electron)));
2745
2746 const auto* empty = Manager::Instance().getVariable("mostB2BInList(testEmptyList, E)");
2747 EXPECT_TRUE(std::isnan(std::get<double>(empty->function(electron))));
2748
2749 const auto* mostB2B = Manager::Instance().getVariable("mostB2BInList(testGammaList, E)");
2750 EXPECT_FLOAT_EQ(std::get<double>(mostB2B->function(electron)), 1.7);
2751
2752 const auto* mostB2BCMS = Manager::Instance().getVariable("useCMSFrame(mostB2BInList(testGammaList, E))");
2753 EXPECT_FLOAT_EQ(std::get<double>(mostB2BCMS->function(electron)), 1.5848758); // the energy gets smeared because of boost
2754
2755 const auto* mostB2BCMSLabE = Manager::Instance().getVariable("useCMSFrame(mostB2BInList(testGammaList, useLabFrame(E)))");
2756 EXPECT_FLOAT_EQ(std::get<double>(mostB2BCMSLabE->function(electron)), 1.7); // aaand should be back to the lab frame value
2757 }
2758 }
2759
2760 TEST_F(MetaVariableTest, totalEnergyOfParticlesInList)
2761 {
2762 // we need the particles StoreArray
2763 StoreArray<Particle> particles;
2765
2766 // create a photon list for testing
2767 StoreObjPtr<ParticleList> gammalist("testGammaList");
2769 gammalist.registerInDataStore(flags);
2771 gammalist.create();
2772 gammalist->initialize(22, "testGammaList");
2773
2774 // create some photons in an stdvector
2775 std::vector<Particle> gammavector = {
2776 Particle({0.5, 0.4, 0.4, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
2777 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
2778 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
2779 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
2780 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
2781 };
2782
2783 // put the photons in the StoreArray
2784 for (const auto& g : gammavector)
2785 particles.appendNew(g);
2786
2787 // put the photons in the test list
2788 for (size_t i = 0; i < gammavector.size(); i++)
2789 gammalist->addParticle(i, 22, Particle::c_Unflavored);
2790
2791 // get their total energy
2792 const Manager::Var* vnonsense = Manager::Instance().getVariable(
2793 "totalEnergyOfParticlesInList(NONEXISTANTLIST)");
2794 const Manager::Var* vsensible = Manager::Instance().getVariable(
2795 "totalEnergyOfParticlesInList(testGammaList)");
2796
2797 // -
2798 EXPECT_B2FATAL(std::get<double>(vnonsense->function(nullptr)));
2799 EXPECT_FLOAT_EQ(std::get<double>(vsensible->function(nullptr)), 4.3);
2800 }
2801 TEST_F(MetaVariableTest, totalPxOfParticlesInList)
2802 {
2803 // we need the particles StoreArray
2804 StoreArray<Particle> particles;
2806
2807 // create a photon list for testing
2808 StoreObjPtr<ParticleList> gammalist("testGammaList");
2810 gammalist.registerInDataStore(flags);
2812 gammalist.create();
2813 gammalist->initialize(22, "testGammaList");
2814
2815 // create some photons in an stdvector
2816 std::vector<Particle> gammavector = {
2817 Particle({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
2818 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
2819 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
2820 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
2821 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
2822 };
2823
2824 // put the photons in the StoreArray
2825 for (const auto& g : gammavector)
2826 particles.appendNew(g);
2827
2828 // put the photons in the test list
2829 for (size_t i = 0; i < gammavector.size(); i++)
2830 gammalist->addParticle(i, 22, Particle::c_Unflavored);
2831
2832 // get their total energy
2833 const Manager::Var* vnonsense = Manager::Instance().getVariable(
2834 "totalPxOfParticlesInList(NONEXISTANTLIST)");
2835 const Manager::Var* vsensible = Manager::Instance().getVariable(
2836 "totalPxOfParticlesInList(testGammaList)");
2837
2838 // -
2839 EXPECT_B2FATAL(std::get<double>(vnonsense->function(nullptr)));
2840 EXPECT_FLOAT_EQ(std::get<double>(vsensible->function(nullptr)), 2.2);
2841 }
2842 TEST_F(MetaVariableTest, totalPyOfParticlesInList)
2843 {
2844 // we need the particles StoreArray
2845 StoreArray<Particle> particles;
2847
2848 // create a photon list for testing
2849 StoreObjPtr<ParticleList> gammalist("testGammaList");
2851 gammalist.registerInDataStore(flags);
2853 gammalist.create();
2854 gammalist->initialize(22, "testGammaList");
2855
2856 // create some photons in an stdvector
2857 std::vector<Particle> gammavector = {
2858 Particle({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
2859 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
2860 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
2861 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
2862 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
2863 };
2864
2865 // put the photons in the StoreArray
2866 for (const auto& g : gammavector)
2867 particles.appendNew(g);
2868
2869 // put the photons in the test list
2870 for (size_t i = 0; i < gammavector.size(); i++)
2871 gammalist->addParticle(i, 22, Particle::c_Unflavored);
2872
2873 // get their total energy
2874 const Manager::Var* vnonsense = Manager::Instance().getVariable(
2875 "totalPyOfParticlesInList(NONEXISTANTLIST)");
2876 const Manager::Var* vsensible = Manager::Instance().getVariable(
2877 "totalPyOfParticlesInList(testGammaList)");
2878
2879 // -
2880 EXPECT_B2FATAL(std::get<double>(vnonsense->function(nullptr)));
2881 EXPECT_FLOAT_EQ(std::get<double>(vsensible->function(nullptr)), 1.5);
2882 }
2883 TEST_F(MetaVariableTest, totalPzOfParticlesInList)
2884 {
2885 // we need the particles StoreArray
2886 StoreArray<Particle> particles;
2888
2889 // create a photon list for testing
2890 StoreObjPtr<ParticleList> gammalist("testGammaList");
2892 gammalist.registerInDataStore(flags);
2894 gammalist.create();
2895 gammalist->initialize(22, "testGammaList");
2896
2897 // create some photons in an stdvector
2898 std::vector<Particle> gammavector = {
2899 Particle({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
2900 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
2901 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
2902 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
2903 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
2904 };
2905
2906 // put the photons in the StoreArray
2907 for (const auto& g : gammavector)
2908 particles.appendNew(g);
2909
2910 // put the photons in the test list
2911 for (size_t i = 0; i < gammavector.size(); i++)
2912 gammalist->addParticle(i, 22, Particle::c_Unflavored);
2913
2914 // get their total energy
2915 const Manager::Var* vnonsense = Manager::Instance().getVariable(
2916 "totalPzOfParticlesInList(NONEXISTANTLIST)");
2917 const Manager::Var* vsensible = Manager::Instance().getVariable(
2918 "totalPzOfParticlesInList(testGammaList)");
2919
2920 // -
2921 EXPECT_B2FATAL(std::get<double>(vnonsense->function(nullptr)));
2922 EXPECT_FLOAT_EQ(std::get<double>(vsensible->function(nullptr)), 3.1);
2923 }
2924 TEST_F(MetaVariableTest, maxPtInList)
2925 {
2926 // we need the particles StoreArray
2927 StoreArray<Particle> particles;
2929
2930 // create a photon list for testing
2931 StoreObjPtr<ParticleList> gammalist("testGammaList");
2933 gammalist.registerInDataStore(flags);
2935 gammalist.create();
2936 gammalist->initialize(22, "testGammaList");
2937
2938 // create some photons in an stdvector
2939 std::vector<Particle> gammavector = {
2940 Particle({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
2941 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
2942 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
2943 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
2944 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
2945 };
2946
2947 // put the photons in the StoreArray
2948 for (const auto& g : gammavector)
2949 particles.appendNew(g);
2950
2951 // put the photons in the test list
2952 for (size_t i = 0; i < gammavector.size(); i++)
2953 gammalist->addParticle(i, 22, Particle::c_Unflavored);
2954
2955 // get their total energy
2956 const Manager::Var* vnonsense = Manager::Instance().getVariable(
2957 "maxPtInList(NONEXISTANTLIST)");
2958 const Manager::Var* vsensible = Manager::Instance().getVariable(
2959 "maxPtInList(testGammaList)");
2960
2961 // -
2962 EXPECT_B2FATAL(std::get<double>(vnonsense->function(nullptr)));
2963 EXPECT_FLOAT_EQ(std::get<double>(vsensible->function(nullptr)), sqrt(0.5 * 0.5 + 0.4 * 0.4));
2964 }
2965
2966
2967 TEST_F(MetaVariableTest, numberOfNonOverlappingParticles)
2968 {
2969 StoreArray<Particle> particles;
2971
2972 StoreObjPtr<ParticleList> outputList("pList1");
2974 outputList.registerInDataStore(flags);
2976 outputList.create();
2977 outputList->initialize(22, "pList1");
2978
2979 auto* p1 = particles.appendNew(Particle({0.5, 0.4, 0.5, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2));
2980 auto* p2 = particles.appendNew(Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3));
2981 auto* p3 = particles.appendNew(Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4));
2982
2983 outputList->addParticle(0, 22, Particle::c_Unflavored);
2984 outputList->addParticle(1, 22, Particle::c_Unflavored);
2985
2986 const Manager::Var* var = Manager::Instance().getVariable("numberOfNonOverlappingParticles(pList1)");
2987 ASSERT_NE(var, nullptr);
2988 EXPECT_EQ(std::get<int>(var->function(p1)), 1);
2989 EXPECT_EQ(std::get<int>(var->function(p2)), 1);
2990 EXPECT_EQ(std::get<int>(var->function(p3)), 2);
2991
2992 }
2993
2994 TEST_F(MetaVariableTest, veto)
2995 {
2996 StoreArray<Particle> particles;
2998
2999 const Particle* p = particles.appendNew(Particle({0.8, 0.8, 1.131370849898476039041351, 1.6}, 22,
3000 Particle::c_Unflavored, Particle::c_Undefined, 1));
3001
3002 StoreObjPtr<ParticleList> outputList("pList1");
3004 outputList.registerInDataStore(flags);
3006 outputList.create();
3007 outputList->initialize(22, "pList1");
3008
3009 particles.appendNew(Particle({0.5, 0.4953406774856531014212777, 0.5609256753154148484773173, 0.9}, 22,
3010 Particle::c_Unflavored, Particle::c_Undefined, 2)); //m=0.135
3011 particles.appendNew(Particle({0.5, 0.2, 0.72111, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3)); //m=0.3582
3012 particles.appendNew(Particle({0.4, 0.2, 0.78102, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)); //m=0.3908
3013 particles.appendNew(Particle({0.5, 0.4, 0.89443, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 5)); //m=0.2369
3014 particles.appendNew(Particle({0.3, 0.3, 0.42426, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 6)); //m=0.0036
3015
3016 outputList->addParticle(1, 22, Particle::c_Unflavored);
3017 outputList->addParticle(2, 22, Particle::c_Unflavored);
3018 outputList->addParticle(3, 22, Particle::c_Unflavored);
3019 outputList->addParticle(4, 22, Particle::c_Unflavored);
3020 outputList->addParticle(5, 22, Particle::c_Unflavored);
3021
3022 StoreObjPtr<ParticleList> outputList2("pList2");
3024 outputList2.registerInDataStore(flags);
3026 outputList2.create();
3027 outputList2->initialize(22, "pList2");
3028
3029 particles.appendNew(Particle({0.5, -0.4, 0.63246, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 7)); //m=1.1353
3030 particles.appendNew(Particle({0.5, 0.2, 0.72111, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 8)); //m=0.3582
3031 particles.appendNew(Particle({0.4, 0.2, 0.78102, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 9)); //m=0.3908
3032 particles.appendNew(Particle({0.5, 0.4, 0.89443, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 10)); //m=0.2369
3033 particles.appendNew(Particle({0.3, 0.3, 0.42426, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 11)); //m=0.0036
3034
3035 outputList2->addParticle(6, 22, Particle::c_Unflavored);
3036 outputList2->addParticle(7, 22, Particle::c_Unflavored);
3037 outputList2->addParticle(8, 22, Particle::c_Unflavored);
3038 outputList2->addParticle(9, 22, Particle::c_Unflavored);
3039 outputList2->addParticle(10, 22, Particle::c_Unflavored);
3040
3041 const Manager::Var* var = Manager::Instance().getVariable("veto(pList1, 0.130 < M < 0.140, 22)");
3042 ASSERT_NE(var, nullptr);
3043 EXPECT_TRUE(std::get<bool>(var->function(p)));
3044
3045 var = Manager::Instance().getVariable("veto(pList2, 0.130 < M < 0.140, 22)");
3046 ASSERT_NE(var, nullptr);
3047 EXPECT_FALSE(std::get<bool>(var->function(p)));
3048
3049 }
3050
3051 TEST_F(MetaVariableTest, averageValueInList)
3052 {
3053 // we need the particles StoreArray
3054 StoreArray<Particle> particles;
3056
3057 // create a photon list for testing
3058 StoreObjPtr<ParticleList> gammalist("testGammaList");
3060 gammalist.registerInDataStore(flags);
3062 gammalist.create();
3063 gammalist->initialize(22, "testGammaList");
3064
3065 // create some photons in an stdvector
3066 std::vector<Particle> gammavector = {
3067 Particle({0.5, 0.4, 0.4, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
3068 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
3069 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
3070 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
3071 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
3072 };
3073
3074 // put the photons in the StoreArray
3075 for (const auto& g : gammavector)
3076 particles.appendNew(g);
3077
3078 // put the photons in the test list
3079 for (size_t i = 0; i < gammavector.size(); i++)
3080 gammalist->addParticle(i, 22, Particle::c_Unflavored);
3081
3082 // get the average px, py, pz, E of the gammas in the list
3083 const Manager::Var* vmeanpx = Manager::Instance().getVariable(
3084 "averageValueInList(testGammaList, px)");
3085 const Manager::Var* vmeanpy = Manager::Instance().getVariable(
3086 "averageValueInList(testGammaList, py)");
3087 const Manager::Var* vmeanpz = Manager::Instance().getVariable(
3088 "averageValueInList(testGammaList, pz)");
3089 const Manager::Var* vmeanE = Manager::Instance().getVariable(
3090 "averageValueInList(testGammaList, E)");
3091
3092 EXPECT_FLOAT_EQ(std::get<double>(vmeanpx->function(nullptr)), 0.44);
3093 EXPECT_FLOAT_EQ(std::get<double>(vmeanpy->function(nullptr)), 0.3);
3094 EXPECT_FLOAT_EQ(std::get<double>(vmeanpz->function(nullptr)), 0.6);
3095 EXPECT_FLOAT_EQ(std::get<double>(vmeanE->function(nullptr)), 0.86);
3096
3097 // wrong number of arguments (no variable provided)
3098 EXPECT_B2FATAL(Manager::Instance().getVariable("averageValueInList(testGammaList)"));
3099
3100 // non-existing variable
3101 EXPECT_B2FATAL(Manager::Instance().getVariable("averageValueInList(testGammaList, NONEXISTANTVARIABLE)"));
3102
3103 // non-existing list
3104 const Manager::Var* vnolist = Manager::Instance().getVariable(
3105 "averageValueInList(NONEXISTANTLIST, px)");
3106
3107 EXPECT_B2FATAL(std::get<double>(vnolist->function(nullptr)));
3108 }
3109
3110 TEST_F(MetaVariableTest, medianValueInList)
3111 {
3112 // we need the particles StoreArray
3113 StoreArray<Particle> particles;
3115
3116 // create two photon lists for testing (one with odd and one with even number of particles)
3117 StoreObjPtr<ParticleList> oddgammalist("oddGammaList");
3119 oddgammalist.registerInDataStore(flags);
3121 oddgammalist.create();
3122 oddgammalist->initialize(22, "oddGammaList");
3123 StoreObjPtr<ParticleList> evengammalist("evenGammaList");
3125 evengammalist.registerInDataStore(flags);
3127 evengammalist.create();
3128 evengammalist->initialize(22, "evenGammaList");
3129
3130 // create some photons in an stdvector
3131 std::vector<Particle> gammavector = {
3132 Particle({0.5, 0.4, 0.4, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
3133 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
3134 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
3135 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
3136 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
3137 };
3138
3139 // put the photons in the StoreArray
3140 for (const auto& g : gammavector)
3141 particles.appendNew(g);
3142
3143 // put the photons in the test lists
3144 oddgammalist->addParticle(0, 22, Particle::c_Unflavored);
3145 for (size_t i = 1; i < gammavector.size(); i++) {
3146 oddgammalist->addParticle(i, 22, Particle::c_Unflavored);
3147 evengammalist->addParticle(i, 22, Particle::c_Unflavored);
3148 }
3149
3150 // get the median px, py, pz, E of the gammas in the list with odd number of particles
3151 const Manager::Var* voddmedianpx = Manager::Instance().getVariable(
3152 "medianValueInList(oddGammaList, px)");
3153 const Manager::Var* voddmedianpy = Manager::Instance().getVariable(
3154 "medianValueInList(oddGammaList, py)");
3155 const Manager::Var* voddmedianpz = Manager::Instance().getVariable(
3156 "medianValueInList(oddGammaList, pz)");
3157 const Manager::Var* voddmedianE = Manager::Instance().getVariable(
3158 "medianValueInList(oddGammaList, E)");
3159
3160 EXPECT_FLOAT_EQ(std::get<double>(voddmedianpx->function(nullptr)), 0.5);
3161 EXPECT_FLOAT_EQ(std::get<double>(voddmedianpy->function(nullptr)), 0.3);
3162 EXPECT_FLOAT_EQ(std::get<double>(voddmedianpz->function(nullptr)), 0.7);
3163 EXPECT_FLOAT_EQ(std::get<double>(voddmedianE->function(nullptr)), 0.9);
3164
3165 // get the median px, py, pz, E of the gammas in the list with odd number of particles
3166 const Manager::Var* vevenmedianpx = Manager::Instance().getVariable(
3167 "medianValueInList(evenGammaList, px)");
3168 const Manager::Var* vevenmedianpy = Manager::Instance().getVariable(
3169 "medianValueInList(evenGammaList, py)");
3170 const Manager::Var* vevenmedianpz = Manager::Instance().getVariable(
3171 "medianValueInList(evenGammaList, pz)");
3172 const Manager::Var* vevenmedianE = Manager::Instance().getVariable(
3173 "medianValueInList(evenGammaList, E)");
3174
3175 EXPECT_FLOAT_EQ(std::get<double>(vevenmedianpx->function(nullptr)), 0.45);
3176 EXPECT_FLOAT_EQ(std::get<double>(vevenmedianpy->function(nullptr)), 0.25);
3177 EXPECT_FLOAT_EQ(std::get<double>(vevenmedianpz->function(nullptr)), 0.7);
3178 EXPECT_FLOAT_EQ(std::get<double>(vevenmedianE->function(nullptr)), 0.9);
3179
3180 // wrong number of arguments (no variable provided)
3181 EXPECT_B2FATAL(Manager::Instance().getVariable("medianValueInList(oddGammaList)"));
3182
3183 // non-existing variable
3184 EXPECT_B2FATAL(Manager::Instance().getVariable("medianValueInList(oddGammaList, NONEXISTANTVARIABLE)"));
3185
3186 // non-existing list
3187 const Manager::Var* vnolist = Manager::Instance().getVariable(
3188 "medianValueInList(NONEXISTANTLIST, px)");
3189
3190 EXPECT_B2FATAL(std::get<double>(vnolist->function(nullptr)));
3191 }
3192
3193 TEST_F(MetaVariableTest, productValueInList)
3194 {
3195 // we need the particles StoreArray
3196 StoreArray<Particle> particles;
3198
3199 // create a photon list for testing
3200 StoreObjPtr<ParticleList> gammalist("testGammaList");
3202 gammalist.registerInDataStore(flags);
3204 gammalist.create();
3205 gammalist->initialize(22, "testGammaList");
3206
3207 // create some photons in an stdvector
3208 std::vector<Particle> gammavector = {
3209 Particle({0.5, 0.4, 0.4, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
3210 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
3211 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
3212 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
3213 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
3214 };
3215
3216 // put the photons in the StoreArray
3217 for (const auto& g : gammavector)
3218 particles.appendNew(g);
3219
3220 // put the photons in the test list
3221 for (size_t i = 0; i < gammavector.size(); i++)
3222 gammalist->addParticle(i, 22, Particle::c_Unflavored);
3223
3224 // get the product of the px, py, pz, E of the gammas in the list
3225 const Manager::Var* vproductpx = Manager::Instance().getVariable(
3226 "productValueInList(testGammaList, px)");
3227 const Manager::Var* vproductpy = Manager::Instance().getVariable(
3228 "productValueInList(testGammaList, py)");
3229 const Manager::Var* vproductpz = Manager::Instance().getVariable(
3230 "productValueInList(testGammaList, pz)");
3231 const Manager::Var* vproductE = Manager::Instance().getVariable(
3232 "productValueInList(testGammaList, E)");
3233
3234 EXPECT_FLOAT_EQ(std::get<double>(vproductpx->function(nullptr)), 0.015);
3235 EXPECT_FLOAT_EQ(std::get<double>(vproductpy->function(nullptr)), 0.00192);
3236 EXPECT_FLOAT_EQ(std::get<double>(vproductpz->function(nullptr)), 0.06272);
3237 EXPECT_FLOAT_EQ(std::get<double>(vproductE->function(nullptr)), 0.42768);
3238
3239 // wrong number of arguments (no variable provided)
3240 EXPECT_B2FATAL(Manager::Instance().getVariable("productValueInList(testGammaList)"));
3241
3242 // non-existing variable
3243 EXPECT_B2FATAL(Manager::Instance().getVariable("productValueInList(testGammaList, NONEXISTANTVARIABLE)"));
3244
3245 // non-existing list
3246 const Manager::Var* vnolist = Manager::Instance().getVariable(
3247 "productValueInList(NONEXISTANTLIST, px)");
3248
3249 EXPECT_B2FATAL(std::get<double>(vnolist->function(nullptr)));
3250 }
3251
3252 TEST_F(MetaVariableTest, sumValueInList)
3253 {
3254 // we need the particles StoreArray
3255 StoreArray<Particle> particles;
3257
3258 // create a photon list for testing
3259 StoreObjPtr<ParticleList> gammalist("testGammaList");
3261 gammalist.registerInDataStore(flags);
3263 gammalist.create();
3264 gammalist->initialize(22, "testGammaList");
3265
3266 // create some photons in an stdvector
3267 std::vector<Particle> gammavector = {
3268 Particle({0.5, 0.4, 0.4, 0.8}, 22, Particle::c_Unflavored, Particle::c_Undefined, 0),
3269 Particle({0.5, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 1),
3270 Particle({0.4, 0.2, 0.7, 0.9}, 22, Particle::c_Unflavored, Particle::c_Undefined, 2),
3271 Particle({0.5, 0.4, 0.8, 1.1}, 22, Particle::c_Unflavored, Particle::c_Undefined, 3),
3272 Particle({0.3, 0.3, 0.4, 0.6}, 22, Particle::c_Unflavored, Particle::c_Undefined, 4)
3273 };
3274
3275 // put the photons in the StoreArray
3276 for (const auto& g : gammavector)
3277 particles.appendNew(g);
3278
3279 // put the photons in the test list
3280 for (size_t i = 0; i < gammavector.size(); i++)
3281 gammalist->addParticle(i, 22, Particle::c_Unflavored);
3282
3283 // get the summed px, py, pz, E of the gammas in the list
3284 const Manager::Var* vsumpx = Manager::Instance().getVariable(
3285 "sumValueInList(testGammaList, px)");
3286 const Manager::Var* vsumpy = Manager::Instance().getVariable(
3287 "sumValueInList(testGammaList, py)");
3288 const Manager::Var* vsumpz = Manager::Instance().getVariable(
3289 "sumValueInList(testGammaList, pz)");
3291 "sumValueInList(testGammaList, E)");
3292
3293 EXPECT_FLOAT_EQ(std::get<double>(vsumpx->function(nullptr)), 2.2);
3294 EXPECT_FLOAT_EQ(std::get<double>(vsumpy->function(nullptr)), 1.5);
3295 EXPECT_FLOAT_EQ(std::get<double>(vsumpz->function(nullptr)), 3.0);
3296 EXPECT_FLOAT_EQ(std::get<double>(vsumE->function(nullptr)), 4.3);
3297
3298 // wrong number of arguments (no variable provided)
3299 EXPECT_B2FATAL(Manager::Instance().getVariable("sumValueInList(testGammaList)"));
3300
3301 // non-existing variable
3302 EXPECT_B2FATAL(Manager::Instance().getVariable("sumValueInList(testGammaList, NONEXISTANTVARIABLE)"));
3303
3304 // non-existing list
3305 const Manager::Var* vnolist = Manager::Instance().getVariable(
3306 "sumValueInList(NONEXISTANTLIST, px)");
3307
3308 EXPECT_B2FATAL(std::get<double>(vnolist->function(nullptr)));
3309 }
3310
3311 TEST_F(MetaVariableTest, pValueCombination)
3312 {
3313 PxPyPzEVector momentum;
3314 StoreArray<Particle> particles;
3315 std::vector<int> daughterIndices;
3316 Particle KS(PxPyPzEVector(1.164, 1.55200, 0, 2), 310, Particle::c_Unflavored, Particle::c_Composite, 0);
3317 KS.setPValue(0.1);
3318 momentum += KS.get4Vector();
3319 Particle* newDaughters = particles.appendNew(KS);
3320 daughterIndices.push_back(newDaughters->getArrayIndex());
3321 Particle Jpsi(PxPyPzEVector(-1, 1, 1, 3.548), 443, Particle::c_Unflavored, Particle::c_Composite, 1);
3322 Jpsi.setPValue(0.9);
3323 momentum += Jpsi.get4Vector();
3324 newDaughters = particles.appendNew(Jpsi);
3325 daughterIndices.push_back(newDaughters->getArrayIndex());
3326 Particle* B = particles.appendNew(momentum, 521, Particle::c_Flavored, daughterIndices);
3327 B->setPValue(0.5);
3328
3329 const Manager::Var* singlePvalue = Manager::Instance().getVariable("pValueCombination(chiProb)");
3330 ASSERT_NE(singlePvalue, nullptr);
3331 EXPECT_FLOAT_EQ(std::get<double>(singlePvalue->function(B)), 0.5);
3332
3333 const Manager::Var* twoPvalues = Manager::Instance().getVariable("pValueCombination(chiProb, daughter(0, chiProb))");
3334 ASSERT_NE(twoPvalues, nullptr);
3335 EXPECT_FLOAT_EQ(std::get<double>(twoPvalues->function(B)), 0.05 * (1 - log(0.05)));
3336
3337 const Manager::Var* threePvalues =
3338 Manager::Instance().getVariable("pValueCombination(chiProb, daughter(0, chiProb), daughter(1, chiProb))");
3339 ASSERT_NE(threePvalues, nullptr);
3340 EXPECT_FLOAT_EQ(std::get<double>(threePvalues->function(B)), 0.045 * (1 - log(0.045) + 0.5 * log(0.045) * log(0.045)));
3341
3342 // wrong number of arguments
3343 EXPECT_B2FATAL(Manager::Instance().getVariable("pValueCombination()"));
3344
3345 // non-existing variable
3346 EXPECT_B2FATAL(Manager::Instance().getVariable("pValueCombination(chiProb, NONEXISTANTVARIABLE)"));
3347 }
3348
3349
3350 TEST_F(MetaVariableTest, daughterCombinationOneGeneration)
3351 {
3352 const int nDaughters = 5;
3353 PxPyPzEVector momentum(0, 0, 0, 0);
3354 StoreArray<Particle> particles;
3355 std::vector<int> daughterIndices;
3356 std::vector<PxPyPzEVector> daughterMomenta;
3357
3358 for (int i = 0; i < nDaughters; i++) {
3359 PxPyPzEVector mom(1, i * 0.5, 1, i * 1.0 + 2.0);
3360 Particle d(mom, (i % 2) ? 111 : 113);
3361 Particle* newDaughters = particles.appendNew(d);
3362 daughterIndices.push_back(newDaughters->getArrayIndex());
3363 daughterMomenta.push_back(mom);
3364 momentum = momentum + mom;
3365 }
3366 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Flavored, daughterIndices);
3367
3368 // Test the invariant mass of several combinations
3369 const Manager::Var* var = Manager::Instance().getVariable("daughterCombination(M, 0,1,2)");
3370 double M_test = (daughterMomenta[0] + daughterMomenta[1] + daughterMomenta[2]).mag();
3371 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), M_test);
3372
3373 var = Manager::Instance().getVariable("daughterCombination(M, 0,4)");
3374 M_test = (daughterMomenta[0] + daughterMomenta[4]).mag();
3375 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), M_test);
3376
3377
3378 // Try with a non-lorentz invariant quantity
3379 var = Manager::Instance().getVariable("daughterCombination(p, 1, 0, 4)");
3380 double p_test = (daughterMomenta[0] + daughterMomenta[1] + daughterMomenta[4]).P();
3381 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), p_test);
3382
3383
3384 // errors and bad stuff
3385 EXPECT_B2FATAL(Manager::Instance().getVariable("daughterCombination(aVeryNonExistingVariableSillyName, 1, 0, 4)"));
3386
3387 var = Manager::Instance().getVariable("daughterCombination(M, 1, 0, 100)");
3388 EXPECT_B2WARNING(std::get<double>(var->function(p)));
3389 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3390
3391
3392 var = Manager::Instance().getVariable("daughterCombination(M, 1, -1)");
3393 EXPECT_B2WARNING(std::get<double>(var->function(p)));
3394 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3395
3396
3397 var = Manager::Instance().getVariable("daughterCombination(M, 1, 0:1:0:0:1)");
3398 EXPECT_B2WARNING(std::get<double>(var->function(p)));
3399 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3400
3401 }
3402
3403
3404 TEST_F(MetaVariableTest, daughterCombinationTwoGenerations)
3405 {
3406 StoreArray<Particle> particles;
3407
3408 // make a 1 -> 3 particle
3409
3410 PxPyPzEVector momentum_1(0, 0, 0, 0);
3411 std::vector<PxPyPzEVector> daughterMomenta_1;
3412 std::vector<int> daughterIndices_1;
3413
3414 for (int i = 0; i < 3; i++) {
3415 PxPyPzEVector mom(i * 0.2, 1, 1, i * 1.0 + 2.0);
3416 Particle d(mom, (i % 2) ? 111 : 113);
3417 Particle* newDaughters = particles.appendNew(d);
3418 daughterIndices_1.push_back(newDaughters->getArrayIndex());
3419 daughterMomenta_1.push_back(mom);
3420 momentum_1 = momentum_1 + mom;
3421 }
3422
3423 const Particle* compositeDau_1 = particles.appendNew(momentum_1, 411, Particle::c_Flavored, daughterIndices_1);
3424
3425
3426 // make a 1 -> 2 particle
3427
3428 PxPyPzEVector momentum_2(0, 0, 0, 0);
3429 std::vector<PxPyPzEVector> daughterMomenta_2;
3430 std::vector<int> daughterIndices_2;
3431
3432 for (int i = 0; i < 2; i++) {
3433 PxPyPzEVector mom(1, 1, i * 0.3, i * 1.0 + 2.0);
3434 Particle d(mom, (i % 2) ? 111 : 113);
3435 Particle* newDaughters = particles.appendNew(d);
3436 daughterIndices_2.push_back(newDaughters->getArrayIndex());
3437 daughterMomenta_2.push_back(mom);
3438 momentum_2 = momentum_2 + mom;
3439 }
3440
3441 const Particle* compositeDau_2 = particles.appendNew(momentum_2, 411, Particle::c_Flavored, daughterIndices_2);
3442
3443
3444 // make the composite particle
3445 std::vector<int> daughterIndices = {compositeDau_1->getArrayIndex(), compositeDau_2->getArrayIndex()};
3446 const Particle* p = particles.appendNew(momentum_2 + momentum_1, 111, Particle::c_Unflavored, daughterIndices);
3447
3448
3449 // Test the invariant mass of several combinations
3450 const Manager::Var* var = Manager::Instance().getVariable("daughterCombination(M, 0,1)");
3451
3452 double M_test = (momentum_1 + momentum_2).mag();
3453 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), M_test);
3454
3455 // this should be the mass of the first daughter
3456 var = Manager::Instance().getVariable("daughterCombination(M, 0:0, 0:1, 0:2)");
3457 M_test = (momentum_1).mag();
3458 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), M_test);
3459
3460 // this should be a generic combinations
3461 var = Manager::Instance().getVariable("daughterCombination(M, 0:0, 0:1, 1:0)");
3462 M_test = (daughterMomenta_1[0] + daughterMomenta_1[1] + daughterMomenta_2[0]).mag();
3463 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), M_test);
3464
3465 }
3466
3467
3468 TEST_F(MetaVariableTest, useAlternativeDaughterHypothesis)
3469 {
3470 const int nDaughters = 5;
3471 StoreArray<Particle> particles;
3472
3473 // Build a first Particle
3474 PxPyPzEVector momentum(0, 0, 0, 0);
3475 std::vector<int> daughterIndices;
3476 for (int i = 0; i < nDaughters; i++) {
3477 double px = i * 0.1;
3478 double py = i * 0.3;
3479 double pz = -i * 0.1 - 0.2;
3480
3481 PxPyPzEVector mom(px, py, pz, 1);
3482 // all pions
3483 int pdgCode = Const::pion.getPDGCode();
3484 Particle d(mom, pdgCode);
3485 d.updateMass(pdgCode);
3486 mom = d.get4Vector();
3487
3488 Particle* daughters = particles.appendNew(d);
3489 daughterIndices.push_back(daughters->getArrayIndex());
3490 momentum = momentum + mom;
3491 }
3492 const Particle* p = particles.appendNew(momentum, 411, Particle::c_Flavored, daughterIndices);
3493
3494
3495 // Build a second Particle with same momenta, but different mass hyp.
3496 PxPyPzEVector momentumAlt(0, 0, 0, 0);
3497 std::vector<int> daughterIndicesAlt;
3498 for (int i = 0; i < nDaughters; i++) {
3499 double px = i * 0.1;
3500 double py = i * 0.3;
3501 double pz = -i * 0.1 - 0.2;
3502
3503 PxPyPzEVector mom(px, py, pz, 1);
3504 // all pions but the first two
3505 int pdgCode = Const::pion.getPDGCode();
3506 if (i == 0)
3507 pdgCode = Const::proton.getPDGCode(); // a proton
3508 if (i == 1)
3509 pdgCode = Const::kaon.getPDGCode(); // a K
3510 Particle d(mom, pdgCode);
3511 d.updateMass(pdgCode);
3512 mom = d.get4Vector();
3513
3514 Particle* daughters = particles.appendNew(d);
3515 daughterIndicesAlt.push_back(daughters->getArrayIndex());
3516 momentumAlt = momentumAlt + mom;
3517 }
3518 const Particle* pAlt = particles.appendNew(momentumAlt, 411, Particle::c_Flavored, daughterIndicesAlt);
3519
3520
3521 // Test the invariant mass under the alternative hypothesis
3522 std::cout << "mass test" << std::endl;
3523 const Manager::Var* var = Manager::Instance().getVariable("useAlternativeDaughterHypothesis(M, 0:p+,1:K+)");
3524 const Manager::Var* varAlt = Manager::Instance().getVariable("M");
3525 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), std::get<double>(varAlt->function(pAlt)));
3526
3527 // check it's really charge-insensitive...
3528 std::cout << "charge test" << std::endl;
3529 var = Manager::Instance().getVariable("useAlternativeDaughterHypothesis(M, 0:p+,1:K-)");
3530 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), std::get<double>(varAlt->function(pAlt)));
3531
3532 // check the variable is not changing the 3-momentum
3533 std::cout << "momentum test" << std::endl;
3534 var = Manager::Instance().getVariable("useAlternativeDaughterHypothesis(p, 0:p+,1:K-)");
3535 varAlt = Manager::Instance().getVariable("p");
3536 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), std::get<double>(varAlt->function(pAlt)));
3537 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), std::get<double>(varAlt->function(p)));
3538 EXPECT_FLOAT_EQ(std::get<double>(var->function(pAlt)), std::get<double>(varAlt->function(pAlt)));
3539 }
3540
3541
3542
3543
3544 TEST_F(MetaVariableTest, daughterAngle)
3545 {
3546 StoreArray<Particle> particles;
3547
3548 // make a 1 -> 3 particle
3549
3550 PxPyPzEVector momentum_1(0, 0, 0, 0);
3551 std::vector<PxPyPzEVector> daughterMomenta_1;
3552 std::vector<int> daughterIndices_1;
3553
3554 for (int i = 0; i < 3; i++) {
3555 PxPyPzEVector mom(i * 0.2, 1, 1, i * 1.0 + 2.0);
3556 Particle d(mom, (i % 2) ? -11 : 211);
3557 Particle* newDaughters = particles.appendNew(d);
3558 daughterIndices_1.push_back(newDaughters->getArrayIndex());
3559 daughterMomenta_1.push_back(mom);
3560 momentum_1 = momentum_1 + mom;
3561 }
3562
3563 const Particle* compositeDau_1 = particles.appendNew(momentum_1, 411, Particle::c_Flavored, daughterIndices_1);
3564
3565
3566 // make a 1 -> 2 particle
3567
3568 PxPyPzEVector momentum_2(0, 0, 0, 0);
3569 std::vector<PxPyPzEVector> daughterMomenta_2;
3570 std::vector<int> daughterIndices_2;
3571
3572 for (int i = 0; i < 2; i++) {
3573 PxPyPzEVector mom(1, 1, i * 0.3, i * 1.0 + 2.0);
3574 Particle d(mom, (i % 2) ? -11 : 211);
3575 Particle* newDaughters = particles.appendNew(d);
3576 daughterIndices_2.push_back(newDaughters->getArrayIndex());
3577 daughterMomenta_2.push_back(mom);
3578 momentum_2 = momentum_2 + mom;
3579 }
3580
3581 const Particle* compositeDau_2 = particles.appendNew(momentum_2, 411, Particle::c_Flavored, daughterIndices_2);
3582
3583
3584 // make the composite particle
3585 std::vector<int> daughterIndices = {compositeDau_1->getArrayIndex(), compositeDau_2->getArrayIndex()};
3586 const Particle* p = particles.appendNew(momentum_2 + momentum_1, 111, Particle::c_Unflavored, daughterIndices);
3587
3588
3589 // Test the invariant mass of several combinations
3590 const Manager::Var* var = Manager::Instance().getVariable("daughterAngle(0, 1)");
3591 double v_test = acos(momentum_1.Vect().Unit().Dot(momentum_2.Vect().Unit()));
3592
3593 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), v_test);
3594
3595 // this should be a generic combinations
3596 var = Manager::Instance().getVariable("daughterAngle(0:0, 1:0)");
3597 v_test = acos(daughterMomenta_1[0].Vect().Unit().Dot(daughterMomenta_2[0].Vect().Unit()));
3598 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), v_test);
3599
3600 var = Manager::Instance().getVariable("daughterAngle( 1, -1)");
3601 EXPECT_B2WARNING(std::get<double>(var->function(p)));
3602 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3603
3604 var = Manager::Instance().getVariable("daughterAngle(1, 0:1:0:0:1)");
3605 EXPECT_B2WARNING(std::get<double>(var->function(p)));
3606 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3607
3608 }
3609
3610 TEST_F(MetaVariableTest, mcDaughterVariables)
3611 {
3612
3614 StoreArray<Particle> particles;
3615 StoreArray<MCParticle> mcParticles;
3616 particles.registerRelationTo(mcParticles);
3618 // make a 1 -> 3 particle
3619
3620 PxPyPzEVector momentum_1(0, 0, 0, 0);
3621 std::vector<PxPyPzEVector> daughterMomenta_1;
3622 std::vector<int> daughterIndices_1;
3623
3624 for (int i = 0; i < 3; i++) {
3625 PxPyPzEVector mom(i * 0.2, 1, 1, i * 1.0 + 2.0);
3626 Particle d(mom, (i % 2) ? -11 : 211);
3627 Particle* newDaughters = particles.appendNew(d);
3628 daughterIndices_1.push_back(newDaughters->getArrayIndex());
3629 daughterMomenta_1.push_back(mom);
3630 momentum_1 = momentum_1 + mom;
3631
3632 auto* mcParticle = mcParticles.appendNew();
3633 mcParticle->setPDG((i % 2) ? -Const::electron.getPDGCode() : Const::pion.getPDGCode());
3635 mcParticle->set4Vector(mom);
3636 newDaughters->addRelationTo(mcParticle);
3637 }
3638
3639 const Particle* compositeDau_1 = particles.appendNew(momentum_1, 411, Particle::c_Flavored, daughterIndices_1);
3640 auto* mcCompositeDau_1 = mcParticles.appendNew();
3641 mcCompositeDau_1->setPDG(411);
3642 mcCompositeDau_1->setStatus(MCParticle::c_PrimaryParticle);
3643 mcCompositeDau_1->set4Vector(momentum_1);
3644 compositeDau_1->addRelationTo(mcCompositeDau_1);
3645
3646 // make a 1 -> 2 particle
3647
3648 PxPyPzEVector momentum_2(0, 0, 0, 0);
3649 std::vector<PxPyPzEVector> daughterMomenta_2;
3650 std::vector<int> daughterIndices_2;
3651
3652 for (int i = 0; i < 2; i++) {
3653 PxPyPzEVector mom(1, 1, i * 0.3, i * 1.0 + 2.0);
3654 Particle d(mom, (i % 2) ? -11 : 211);
3655 Particle* newDaughters = particles.appendNew(d);
3656 daughterIndices_2.push_back(newDaughters->getArrayIndex());
3657 daughterMomenta_2.push_back(mom);
3658 momentum_2 = momentum_2 + mom;
3659
3660 auto* mcParticle = mcParticles.appendNew();
3661 mcParticle->setPDG((i % 2) ? -Const::electron.getPDGCode() : Const::pion.getPDGCode());
3663 mcParticle->set4Vector(mom);
3664 newDaughters->addRelationTo(mcParticle);
3665 }
3666
3667 const Particle* compositeDau_2 = particles.appendNew(momentum_2, 411, Particle::c_Flavored, daughterIndices_2);
3668 auto* mcCompositeDau_2 = mcParticles.appendNew();
3669 mcCompositeDau_2->setPDG(411);
3670 mcCompositeDau_2->setStatus(MCParticle::c_PrimaryParticle);
3671 mcCompositeDau_2->set4Vector(momentum_2);
3672 compositeDau_2->addRelationTo(mcCompositeDau_2);
3673
3674 // make the composite particle
3675 std::vector<int> daughterIndices = {compositeDau_1->getArrayIndex(), compositeDau_2->getArrayIndex()};
3676 const Particle* p = particles.appendNew(momentum_2 + momentum_1, 111, Particle::c_Unflavored, daughterIndices);
3677
3678
3679 // Test mcDaughterAngle
3680 const Manager::Var* var = Manager::Instance().getVariable("mcDaughterAngle(0, 1)");
3681 double v_test = acos(momentum_1.Vect().Unit().Dot(momentum_2.Vect().Unit()));
3682 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), v_test);
3683
3684 var = Manager::Instance().getVariable("mcDaughterAngle(0:0, 1:0)");
3685 v_test = acos(daughterMomenta_1[0].Vect().Unit().Dot(daughterMomenta_2[0].Vect().Unit()));
3686 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), v_test);
3687
3688 var = Manager::Instance().getVariable("mcDaughterAngle( 1, -1)");
3689 EXPECT_B2WARNING(std::get<double>(var->function(p)));
3690 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3691
3692 var = Manager::Instance().getVariable("mcDaughterAngle(1, 0:1:0:0:1)");
3693 EXPECT_B2WARNING(std::get<double>(var->function(p)));
3694 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3695
3696 // Test mcDaughterDiffOf
3697 var = Manager::Instance().getVariable("mcDaughterDiffOf(0, 1, PDG)");
3698 ASSERT_NE(var, nullptr);
3699 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), 0);
3700
3701 var = Manager::Instance().getVariable("mcDaughterDiffOf(0, NOTINT, PDG)");
3702 ASSERT_NE(var, nullptr);
3703 EXPECT_TRUE(std::isnan(std::get<double>(var->function(p))));
3704
3705 // Test azimuthal angle as well
3706 var = Manager::Instance().getVariable("mcDaughterDiffOf(0, 1, phi)");
3707 ASSERT_NE(var, nullptr);
3708 v_test = momentum_2.Phi() - momentum_1.Phi();
3709 EXPECT_FLOAT_EQ(std::get<double>(var->function(p)), v_test);
3710
3711 }
3712
3713 TEST_F(MetaVariableTest, varForFirstMCAncestorOfType)
3714 {
3716 StoreArray<MCParticle> mcParticles;
3717 StoreArray<Particle> particles;
3718 particles.registerInDataStore();
3719 mcParticles.registerInDataStore();
3720 particles.registerRelationTo(mcParticles);
3721 StoreObjPtr<ParticleList> DList("D0:vartest");
3722 DList.registerInDataStore();
3723 DList.create();
3724 DList->initialize(421, "D0:vartest");
3726 PxPyPzEVector momentum;
3727 PxPyPzEVector momentum_0;
3728 PxPyPzEVector momentum_1;
3729 std::vector<int> D_daughterIndices;
3730 std::vector<int> D_grandDaughterIndices_0;
3731 std::vector<int> D_grandDaughterIndices_1;
3732
3733
3734 // Create MC graph for D -> (K0s -> pi+ + pi-) (K0s -> pi+ + pi-)
3735 MCParticleGraph mcGraph;
3736
3738 MCParticleGraph::GraphParticle& mcg_d_0 = mcGraph.addParticle();
3739 MCParticleGraph::GraphParticle& mcg_d_1 = mcGraph.addParticle();
3740 MCParticleGraph::GraphParticle& mcg_gd_0_0 = mcGraph.addParticle();
3741 MCParticleGraph::GraphParticle& mcg_gd_0_1 = mcGraph.addParticle();
3742 MCParticleGraph::GraphParticle& mcg_gd_1_0 = mcGraph.addParticle();
3743 MCParticleGraph::GraphParticle& mcg_gd_1_1 = mcGraph.addParticle();
3744 MCParticleGraph::GraphParticle& mcg_not_child = mcGraph.addParticle();
3745
3746 mcg_m.setPDG(421);
3747 mcg_m.set4Vector(PxPyPzEVector(7, 7, 7, 7));
3748 mcg_d_0.setPDG(-Const::Kshort.getPDGCode());
3749 mcg_d_0.set4Vector(PxPyPzEVector(6, 6, 6, 6));
3750 mcg_d_1.setPDG(Const::Kshort.getPDGCode());
3751 mcg_d_1.set4Vector(PxPyPzEVector(5, 5, 5, 5));
3752 mcg_gd_0_0.setPDG(Const::pion.getPDGCode());
3753 mcg_gd_0_0.set4Vector(PxPyPzEVector(4, 4, 4, 4));
3754 mcg_gd_0_1.setPDG(-Const::pion.getPDGCode());
3755 mcg_gd_0_1.set4Vector(PxPyPzEVector(3, 3, 3, 3));
3756 mcg_gd_1_0.setPDG(Const::pion.getPDGCode());
3757 mcg_gd_1_0.set4Vector(PxPyPzEVector(2, 1, 2, 2));
3758 mcg_gd_1_1.setPDG(-Const::pion.getPDGCode());
3759 mcg_gd_1_1.set4Vector(PxPyPzEVector(1, 1, 1, 1));
3760 mcg_not_child.setPDG(Const::pion.getPDGCode());
3761 mcg_not_child.set4Vector(PxPyPzEVector(10, 10, 10, 10));
3762
3763 mcg_d_0.comesFrom(mcg_m);
3764 mcg_d_1.comesFrom(mcg_m);
3765 mcg_gd_0_0.comesFrom(mcg_d_0);
3766 mcg_gd_0_1.comesFrom(mcg_d_0);
3767 mcg_gd_1_0.comesFrom(mcg_d_1);
3768 mcg_gd_1_1.comesFrom(mcg_d_1);
3769
3770 mcGraph.generateList();
3771
3772 // Get MC Particles from StoreArray
3773 auto* mc_not_child = mcParticles[0];
3774 auto* mc_m = mcParticles[1];
3775 auto* mc_d_0 = mcParticles[2];
3776 auto* mc_d_1 = mcParticles[3];
3777 auto* mc_gd_0_0 = mcParticles[4];
3778 auto* mc_gd_0_1 = mcParticles[5];
3779 auto* mc_gd_1_0 = mcParticles[6];
3780 auto* mc_gd_1_1 = mcParticles[7];
3781
3782
3783 mc_m->setStatus(MCParticle::c_PrimaryParticle);
3784 mc_d_0->setStatus(MCParticle::c_PrimaryParticle);
3785 mc_d_1->setStatus(MCParticle::c_PrimaryParticle);
3786 mc_gd_0_0->setStatus(MCParticle::c_PrimaryParticle);
3787 mc_gd_0_1->setStatus(MCParticle::c_PrimaryParticle);
3788 mc_gd_1_0->setStatus(MCParticle::c_PrimaryParticle);
3789 mc_gd_1_1->setStatus(MCParticle::c_PrimaryParticle);
3790 mc_not_child->setStatus(MCParticle::c_PrimaryParticle);
3791
3792 // Creation of D decay: D->K0s(->pi pi) K0s(->pi pi)
3793
3794 const Particle* D_gd_0_0 = particles.appendNew(PxPyPzEVector(0.0, 1, 1, 1), 211);
3795 const Particle* D_gd_0_1 = particles.appendNew(PxPyPzEVector(1.0, 1, 1, 1), -211);
3796 const Particle* D_gd_1_0 = particles.appendNew(PxPyPzEVector(2.0, 1, 1, 1), 211);
3797 const Particle* D_gd_1_1 = particles.appendNew(PxPyPzEVector(3.0, 1, 1, 1), -211);
3798
3799 D_grandDaughterIndices_0.push_back(D_gd_0_0->getArrayIndex());
3800 D_grandDaughterIndices_0.push_back(D_gd_0_1->getArrayIndex());
3801 D_grandDaughterIndices_1.push_back(D_gd_1_0->getArrayIndex());
3802 D_grandDaughterIndices_1.push_back(D_gd_1_1->getArrayIndex());
3803 momentum_0 = D_gd_0_0->get4Vector() + D_gd_0_1->get4Vector();
3804 momentum_1 = D_gd_1_0->get4Vector() + D_gd_1_1->get4Vector();
3805
3806
3807 const Particle* D_d_0 = particles.appendNew(momentum_0, 310, Particle::c_Unflavored, D_grandDaughterIndices_0);
3808 const Particle* D_d_1 = particles.appendNew(momentum_1, 310, Particle::c_Unflavored, D_grandDaughterIndices_1);
3809
3810
3811 momentum = D_d_0->get4Vector() + D_d_1->get4Vector();
3812 D_daughterIndices.push_back(D_d_0->getArrayIndex());
3813 D_daughterIndices.push_back(D_d_1->getArrayIndex());
3814
3815 const Particle* D_m = particles.appendNew(momentum, 421, Particle::c_Unflavored, D_daughterIndices);
3816 DList->addParticle(D_m);
3817
3818 // Particle that is not an child
3819 const Particle* not_child = particles.appendNew(PxPyPzEVector(5.0, 1, 1, 1), 211);
3820
3821 // Particle that is not an child and doesn't have MC particle
3822 const Particle* not_child_2 = particles.appendNew(PxPyPzEVector(6.0, 1, 1, 1), 211);
3823
3824 // MC matching
3825 D_gd_0_0->addRelationTo(mc_gd_0_0);
3826 D_gd_0_1->addRelationTo(mc_gd_0_1);
3827 D_gd_1_0->addRelationTo(mc_gd_1_0);
3828 D_gd_1_1->addRelationTo(mc_gd_1_1);
3829 D_d_0->addRelationTo(mc_d_0);
3830 D_d_1->addRelationTo(mc_d_1);
3831 D_m->addRelationTo(mc_m);
3832 not_child->addRelationTo(mc_not_child);
3833
3834 // All pions should have common D mother
3835 const Manager::Var* var_d = Manager::Instance().getVariable("varForFirstMCAncestorOfType(D0, mdstIndex)");
3836 ASSERT_NE(var_d, nullptr);
3837 EXPECT_TRUE(std::get<double>(var_d->function(D_gd_0_0)) >= 0);
3838 EXPECT_FLOAT_EQ(std::get<double>(var_d->function(D_gd_0_0)), std::get<double>(var_d->function(D_gd_0_1)));
3839 EXPECT_FLOAT_EQ(std::get<double>(var_d->function(D_gd_1_0)), std::get<double>(var_d->function(D_gd_1_1)));
3840 EXPECT_FLOAT_EQ(std::get<double>(var_d->function(D_gd_0_0)), std::get<double>(var_d->function(D_gd_1_0)));
3841 EXPECT_FLOAT_EQ(std::get<double>(var_d->function(D_gd_0_1)), std::get<double>(var_d->function(D_gd_1_1)));
3842 EXPECT_TRUE(std::isnan(std::get<double>(var_d->function(not_child))));
3843 EXPECT_TRUE(std::isnan(std::get<double>(var_d->function(not_child_2))));
3844
3845
3846 // // All but they have different K0s mothers
3847 const Manager::Var* var_310 = Manager::Instance().getVariable("varForFirstMCAncestorOfType(310, mdstIndex)");
3848 ASSERT_NE(var_310, nullptr);
3849 EXPECT_FLOAT_EQ(std::get<double>(var_310->function(D_gd_0_0)), std::get<double>(var_310->function(D_gd_0_1)));
3850 EXPECT_FLOAT_EQ(std::get<double>(var_310->function(D_gd_1_0)), std::get<double>(var_310->function(D_gd_1_1)));
3851 EXPECT_NE(std::get<double>(var_310->function(D_gd_0_0)), std::get<double>(var_310->function(D_gd_1_0)));
3852 EXPECT_NE(std::get<double>(var_310->function(D_gd_0_1)), std::get<double>(var_310->function(D_gd_1_1)));
3853 EXPECT_TRUE(std::isnan(std::get<double>(var_310->function(not_child))));
3854 EXPECT_TRUE(std::isnan(std::get<double>(var_310->function(not_child_2))));
3855 EXPECT_FLOAT_EQ(int(std::get<double>(Manager::Instance().getVariable("varForFirstMCAncestorOfType(310, E)")->function(D_gd_0_0))),
3856 10);
3857 }
3858
3859 TEST_F(MetaVariableTest, isDescendantOfList)
3860 {
3862 StoreObjPtr<ParticleList> DList("D0:vartest");
3863 DList.registerInDataStore();
3864 DList.create();
3865 DList->initialize(421, "D0:vartest");
3866 StoreObjPtr<ParticleList> BList("B:vartest");
3867 BList.registerInDataStore();
3868 BList.create();
3869 BList->initialize(521, "B:vartest");
3871
3872 PxPyPzEVector momentum;
3873 PxPyPzEVector momentum_0;
3874 PxPyPzEVector momentum_1;
3875 StoreArray<Particle> particles;
3876 std::vector<int> D_daughterIndices;
3877 std::vector<int> D_grandDaughterIndices_0;
3878 std::vector<int> D_grandDaughterIndices_1;
3879 std::vector<int> B_daughterIndices;
3880 std::vector<int> B_grandDaughterIndices;
3881 std::vector<int> B_grandGrandDaughterIndices;
3882
3883 // Creation of D decay: D->K0s(->pi pi) K0s(->pi pi)
3884
3885 const Particle* D_gd_0_0 = particles.appendNew(PxPyPzEVector(0.0, 1, 1, 1), 211, Particle::c_Flavored, Particle::c_Track, 0);
3886 const Particle* D_gd_0_1 = particles.appendNew(PxPyPzEVector(1.0, 1, 1, 1), -211, Particle::c_Flavored, Particle::c_Track, 1);
3887 const Particle* D_gd_1_0 = particles.appendNew(PxPyPzEVector(2.0, 1, 1, 1), 211, Particle::c_Flavored, Particle::c_Track, 2);
3888 const Particle* D_gd_1_1 = particles.appendNew(PxPyPzEVector(3.0, 1, 1, 1), -211, Particle::c_Flavored, Particle::c_Track, 3);
3889
3890 D_grandDaughterIndices_0.push_back(D_gd_0_0->getArrayIndex());
3891 D_grandDaughterIndices_0.push_back(D_gd_0_1->getArrayIndex());
3892 D_grandDaughterIndices_1.push_back(D_gd_1_0->getArrayIndex());
3893 D_grandDaughterIndices_1.push_back(D_gd_1_1->getArrayIndex());
3894 momentum_0 = D_gd_0_0->get4Vector() + D_gd_0_1->get4Vector();
3895 momentum_1 = D_gd_1_0->get4Vector() + D_gd_1_1->get4Vector();
3896
3897
3898 const Particle* D_d_0 = particles.appendNew(momentum_0, 310, Particle::c_Unflavored, D_grandDaughterIndices_0);
3899 const Particle* D_d_1 = particles.appendNew(momentum_1, 310, Particle::c_Unflavored, D_grandDaughterIndices_1);
3900
3901
3902 momentum = D_d_0->get4Vector() + D_d_1->get4Vector();
3903 D_daughterIndices.push_back(D_d_0->getArrayIndex());
3904 D_daughterIndices.push_back(D_d_1->getArrayIndex());
3905
3906 const Particle* D_m = particles.appendNew(momentum, 421, Particle::c_Unflavored, D_daughterIndices);
3907 DList->addParticle(D_m);
3908
3909 // Creation of B decay B -> D(->K0s(->pi pi) pi) pi
3910
3911 const Particle* B_d_1 = particles.appendNew(PxPyPzEVector(0.0, 1, 1, 1), 211, Particle::c_Flavored, Particle::c_Track, 4);
3912 const Particle* B_gd_0_1 = particles.appendNew(PxPyPzEVector(1.0, 1, 1, 1), -211, Particle::c_Flavored, Particle::c_Track, 5);
3913 const Particle* B_ggd_0_0_0 = particles.appendNew(PxPyPzEVector(2.0, 1, 1, 1), 211, Particle::c_Flavored, Particle::c_Track, 6);
3914 const Particle* B_ggd_0_0_1 = particles.appendNew(PxPyPzEVector(3.0, 1, 1, 1), -211, Particle::c_Flavored, Particle::c_Track, 7);
3915
3916 B_grandGrandDaughterIndices.push_back(B_ggd_0_0_0->getArrayIndex());
3917 B_grandGrandDaughterIndices.push_back(B_ggd_0_0_1->getArrayIndex());
3918 momentum_0 = B_ggd_0_0_0->get4Vector() + B_ggd_0_0_1->get4Vector();
3919 const Particle* B_gd_0_0 = particles.appendNew(momentum_0, 310, Particle::c_Unflavored, B_grandGrandDaughterIndices);
3920
3921 B_grandDaughterIndices.push_back(B_gd_0_0->getArrayIndex());
3922 B_grandDaughterIndices.push_back(B_gd_0_1->getArrayIndex());
3923 momentum_1 = B_gd_0_0->get4Vector() + B_gd_0_1->get4Vector();
3924 const Particle* B_d_0 = particles.appendNew(momentum_1, -411, Particle::c_Unflavored, B_grandDaughterIndices);
3925
3926 B_daughterIndices.push_back(B_d_0->getArrayIndex());
3927 B_daughterIndices.push_back(B_d_1->getArrayIndex());
3928 momentum = B_d_0->get4Vector() + B_d_1->get4Vector();
3929 const Particle* B_m = particles.appendNew(momentum, 521, Particle::c_Unflavored, B_daughterIndices);
3930 BList->addParticle(B_m);
3931
3932 // Particle that is not an child
3933 const Particle* not_child = particles.appendNew(PxPyPzEVector(5.0, 1, 1, 1), 211, Particle::c_Flavored, Particle::c_Track, 8);
3934
3935
3936 const Manager::Var* var_0 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest)");
3937 ASSERT_NE(var_0, nullptr);
3938 EXPECT_TRUE(std::get<bool>(var_0->function(D_gd_0_0)));
3939 EXPECT_TRUE(std::get<bool>(var_0->function(D_gd_0_1)));
3940 EXPECT_TRUE(std::get<bool>(var_0->function(D_gd_1_0)));
3941 EXPECT_TRUE(std::get<bool>(var_0->function(D_gd_1_1)));
3942 EXPECT_TRUE(std::get<bool>(var_0->function(D_d_0)));
3943 EXPECT_TRUE(std::get<bool>(var_0->function(D_d_1)));
3944 EXPECT_FALSE(std::get<bool>(var_0->function(B_ggd_0_0_0)));
3945 EXPECT_FALSE(std::get<bool>(var_0->function(B_ggd_0_0_1)));
3946 EXPECT_FALSE(std::get<bool>(var_0->function(B_gd_0_0)));
3947 EXPECT_FALSE(std::get<bool>(var_0->function(B_gd_0_1)));
3948 EXPECT_FALSE(std::get<bool>(var_0->function(B_d_0)));
3949 EXPECT_FALSE(std::get<bool>(var_0->function(B_d_1)));
3950 EXPECT_FALSE(std::get<bool>(var_0->function(not_child)));
3951
3952 const Manager::Var* var_0a = Manager::Instance().getVariable("isDaughterOfList(D0:vartest)");
3953 ASSERT_NE(var_0a, nullptr);
3954 EXPECT_FALSE(std::get<bool>(var_0a->function(D_gd_0_0)));
3955 EXPECT_FALSE(std::get<bool>(var_0a->function(D_gd_0_1)));
3956 EXPECT_FALSE(std::get<bool>(var_0a->function(D_gd_1_0)));
3957 EXPECT_FALSE(std::get<bool>(var_0a->function(D_gd_1_1)));
3958 EXPECT_TRUE(std::get<bool>(var_0a->function(D_d_0)));
3959 EXPECT_TRUE(std::get<bool>(var_0a->function(D_d_1)));
3960 EXPECT_FALSE(std::get<bool>(var_0a->function(B_ggd_0_0_0)));
3961 EXPECT_FALSE(std::get<bool>(var_0a->function(B_ggd_0_0_1)));
3962 EXPECT_FALSE(std::get<bool>(var_0a->function(B_gd_0_0)));
3963 EXPECT_FALSE(std::get<bool>(var_0a->function(B_gd_0_1)));
3964 EXPECT_FALSE(std::get<bool>(var_0a->function(B_d_0)));
3965 EXPECT_FALSE(std::get<bool>(var_0a->function(B_d_1)));
3966 EXPECT_FALSE(std::get<bool>(var_0a->function(not_child)));
3967
3968 const Manager::Var* var_0b = Manager::Instance().getVariable("isGrandDaughterOfList(D0:vartest)");
3969 ASSERT_NE(var_0b, nullptr);
3970 EXPECT_TRUE(std::get<bool>(var_0b->function(D_gd_0_0)));
3971 EXPECT_TRUE(std::get<bool>(var_0b->function(D_gd_0_1)));
3972 EXPECT_TRUE(std::get<bool>(var_0b->function(D_gd_1_0)));
3973 EXPECT_TRUE(std::get<bool>(var_0b->function(D_gd_1_1)));
3974 EXPECT_FALSE(std::get<bool>(var_0b->function(D_d_0)));
3975 EXPECT_FALSE(std::get<bool>(var_0b->function(D_d_1)));
3976 EXPECT_FALSE(std::get<bool>(var_0b->function(B_ggd_0_0_0)));
3977 EXPECT_FALSE(std::get<bool>(var_0b->function(B_ggd_0_0_1)));
3978 EXPECT_FALSE(std::get<bool>(var_0b->function(B_gd_0_0)));
3979 EXPECT_FALSE(std::get<bool>(var_0b->function(B_gd_0_1)));
3980 EXPECT_FALSE(std::get<bool>(var_0b->function(B_d_0)));
3981 EXPECT_FALSE(std::get<bool>(var_0b->function(B_d_1)));
3982 EXPECT_FALSE(std::get<bool>(var_0b->function(not_child)));
3983
3984 const Manager::Var* var_1 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest, 1)");
3985 ASSERT_NE(var_1, nullptr);
3986 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_0_0)));
3987 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_0_1)));
3988 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_1_0)));
3989 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_1_1)));
3990 EXPECT_TRUE(std::get<bool>(var_1->function(D_d_0)));
3991 EXPECT_TRUE(std::get<bool>(var_1->function(D_d_1)));
3992 EXPECT_FALSE(std::get<bool>(var_1->function(B_ggd_0_0_0)));
3993 EXPECT_FALSE(std::get<bool>(var_1->function(B_ggd_0_0_1)));
3994 EXPECT_FALSE(std::get<bool>(var_1->function(B_gd_0_0)));
3995 EXPECT_FALSE(std::get<bool>(var_1->function(B_gd_0_1)));
3996 EXPECT_FALSE(std::get<bool>(var_1->function(B_d_0)));
3997 EXPECT_FALSE(std::get<bool>(var_1->function(B_d_1)));
3998 EXPECT_FALSE(std::get<bool>(var_1->function(not_child)));
3999
4000 const Manager::Var* var_2 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest, 2)");
4001 ASSERT_NE(var_2, nullptr);
4002 EXPECT_TRUE(std::get<bool>(var_2->function(D_gd_0_0)));
4003 EXPECT_TRUE(std::get<bool>(var_2->function(D_gd_0_1)));
4004 EXPECT_TRUE(std::get<bool>(var_2->function(D_gd_1_0)));
4005 EXPECT_TRUE(std::get<bool>(var_2->function(D_gd_1_1)));
4006 EXPECT_FALSE(std::get<bool>(var_2->function(D_d_0)));
4007 EXPECT_FALSE(std::get<bool>(var_2->function(D_d_1)));
4008 EXPECT_FALSE(std::get<bool>(var_2->function(B_ggd_0_0_0)));
4009 EXPECT_FALSE(std::get<bool>(var_2->function(B_ggd_0_0_1)));
4010 EXPECT_FALSE(std::get<bool>(var_2->function(B_gd_0_0)));
4011 EXPECT_FALSE(std::get<bool>(var_2->function(B_gd_0_1)));
4012 EXPECT_FALSE(std::get<bool>(var_2->function(B_d_0)));
4013 EXPECT_FALSE(std::get<bool>(var_2->function(B_d_1)));
4014 EXPECT_FALSE(std::get<bool>(var_2->function(not_child)));
4015
4016 const Manager::Var* var_3 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest, B:vartest)");
4017 ASSERT_NE(var_3, nullptr);
4018 EXPECT_TRUE(std::get<bool>(var_3->function(D_gd_0_0)));
4019 EXPECT_TRUE(std::get<bool>(var_3->function(D_gd_0_1)));
4020 EXPECT_TRUE(std::get<bool>(var_3->function(D_gd_1_0)));
4021 EXPECT_TRUE(std::get<bool>(var_3->function(D_gd_1_1)));
4022 EXPECT_TRUE(std::get<bool>(var_3->function(D_d_0)));
4023 EXPECT_TRUE(std::get<bool>(var_3->function(D_d_1)));
4024 EXPECT_TRUE(std::get<bool>(var_3->function(B_ggd_0_0_0)));
4025 EXPECT_TRUE(std::get<bool>(var_3->function(B_ggd_0_0_1)));
4026 EXPECT_TRUE(std::get<bool>(var_3->function(B_gd_0_0)));
4027 EXPECT_TRUE(std::get<bool>(var_3->function(B_gd_0_1)));
4028 EXPECT_TRUE(std::get<bool>(var_3->function(B_d_0)));
4029 EXPECT_TRUE(std::get<bool>(var_3->function(B_d_1)));
4030 EXPECT_FALSE(std::get<bool>(var_3->function(not_child)));
4031
4032 const Manager::Var* var_4 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest, B:vartest, -1)");
4033 ASSERT_NE(var_4, nullptr);
4034 EXPECT_TRUE(std::get<bool>(var_4->function(D_gd_0_0)));
4035 EXPECT_TRUE(std::get<bool>(var_4->function(D_gd_0_1)));
4036 EXPECT_TRUE(std::get<bool>(var_4->function(D_gd_1_0)));
4037 EXPECT_TRUE(std::get<bool>(var_4->function(D_gd_1_1)));
4038 EXPECT_TRUE(std::get<bool>(var_4->function(D_d_0)));
4039 EXPECT_TRUE(std::get<bool>(var_4->function(D_d_1)));
4040 EXPECT_TRUE(std::get<bool>(var_4->function(B_ggd_0_0_0)));
4041 EXPECT_TRUE(std::get<bool>(var_4->function(B_ggd_0_0_1)));
4042 EXPECT_TRUE(std::get<bool>(var_4->function(B_gd_0_0)));
4043 EXPECT_TRUE(std::get<bool>(var_4->function(B_gd_0_1)));
4044 EXPECT_TRUE(std::get<bool>(var_4->function(B_d_0)));
4045 EXPECT_TRUE(std::get<bool>(var_4->function(B_d_1)));
4046 EXPECT_FALSE(std::get<bool>(var_4->function(not_child)));
4047
4048 const Manager::Var* var_5 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest, B:vartest, 1)");
4049 ASSERT_NE(var_5, nullptr);
4050 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_0_0)));
4051 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_0_1)));
4052 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_1_0)));
4053 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_1_1)));
4054 EXPECT_TRUE(std::get<bool>(var_5->function(D_d_0)));
4055 EXPECT_TRUE(std::get<bool>(var_5->function(D_d_1)));
4056 EXPECT_FALSE(std::get<bool>(var_5->function(B_ggd_0_0_0)));
4057 EXPECT_FALSE(std::get<bool>(var_5->function(B_ggd_0_0_1)));
4058 EXPECT_FALSE(std::get<bool>(var_5->function(B_gd_0_0)));
4059 EXPECT_FALSE(std::get<bool>(var_5->function(B_gd_0_1)));
4060 EXPECT_TRUE(std::get<bool>(var_5->function(B_d_0)));
4061 EXPECT_TRUE(std::get<bool>(var_5->function(B_d_1)));
4062 EXPECT_FALSE(std::get<bool>(var_5->function(not_child)));
4063
4064 const Manager::Var* var_6 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest, B:vartest, 2)");
4065 ASSERT_NE(var_6, nullptr);
4066 EXPECT_TRUE(std::get<bool>(var_6->function(D_gd_0_0)));
4067 EXPECT_TRUE(std::get<bool>(var_6->function(D_gd_0_1)));
4068 EXPECT_TRUE(std::get<bool>(var_6->function(D_gd_1_0)));
4069 EXPECT_TRUE(std::get<bool>(var_6->function(D_gd_1_1)));
4070 EXPECT_FALSE(std::get<bool>(var_6->function(D_d_0)));
4071 EXPECT_FALSE(std::get<bool>(var_6->function(D_d_1)));
4072 EXPECT_FALSE(std::get<bool>(var_6->function(B_ggd_0_0_0)));
4073 EXPECT_FALSE(std::get<bool>(var_6->function(B_ggd_0_0_1)));
4074 EXPECT_TRUE(std::get<bool>(var_6->function(B_gd_0_0)));
4075 EXPECT_TRUE(std::get<bool>(var_6->function(B_gd_0_1)));
4076 EXPECT_FALSE(std::get<bool>(var_6->function(B_d_0)));
4077 EXPECT_FALSE(std::get<bool>(var_6->function(B_d_1)));
4078 EXPECT_FALSE(std::get<bool>(var_6->function(not_child)));
4079
4080 const Manager::Var* var_7 = Manager::Instance().getVariable("isDescendantOfList(D0:vartest, B:vartest, 3)");
4081 ASSERT_NE(var_7, nullptr);
4082 EXPECT_FALSE(std::get<bool>(var_7->function(D_gd_0_0)));
4083 EXPECT_FALSE(std::get<bool>(var_7->function(D_gd_0_1)));
4084 EXPECT_FALSE(std::get<bool>(var_7->function(D_gd_1_0)));
4085 EXPECT_FALSE(std::get<bool>(var_7->function(D_gd_1_1)));
4086 EXPECT_FALSE(std::get<bool>(var_7->function(D_d_0)));
4087 EXPECT_FALSE(std::get<bool>(var_7->function(D_d_1)));
4088 EXPECT_TRUE(std::get<bool>(var_7->function(B_ggd_0_0_0)));
4089 EXPECT_TRUE(std::get<bool>(var_7->function(B_ggd_0_0_1)));
4090 EXPECT_FALSE(std::get<bool>(var_7->function(B_gd_0_0)));
4091 EXPECT_FALSE(std::get<bool>(var_7->function(B_gd_0_1)));
4092 EXPECT_FALSE(std::get<bool>(var_7->function(B_d_0)));
4093 EXPECT_FALSE(std::get<bool>(var_7->function(B_d_1)));
4094 EXPECT_FALSE(std::get<bool>(var_7->function(not_child)));
4095 }
4096
4097
4098 TEST_F(MetaVariableTest, isMCDescendantOfList)
4099 {
4101 StoreArray<MCParticle> mcParticles;
4102 StoreArray<Particle> particles;
4103 particles.registerInDataStore();
4104 mcParticles.registerInDataStore();
4105 particles.registerRelationTo(mcParticles);
4106 StoreObjPtr<ParticleList> BList("B:vartest");
4107 BList.registerInDataStore();
4108 BList.create();
4109 BList->initialize(521, "B:vartest");
4110 StoreObjPtr<ParticleList> DList("D0:vartest");
4111 DList.registerInDataStore();
4112 DList.create();
4113 DList->initialize(421, "D0:vartest");
4115 PxPyPzEVector momentum;
4116 PxPyPzEVector momentum_0;
4117 PxPyPzEVector momentum_1;
4118 std::vector<int> daughterIndices;
4119 std::vector<int> grandDaughterIndices;
4120 std::vector<int> grandGrandDaughterIndices;
4121 std::vector<int> D_daughterIndices;
4122 std::vector<int> D_grandDaughterIndices_0;
4123 std::vector<int> D_grandDaughterIndices_1;
4124
4125
4126 // Create MC graph for B+ -> (D -> (K0s -> pi+ + pi-) pi-) + pi+
4127 MCParticleGraph mcGraph;
4128
4130 MCParticleGraph::GraphParticle& mcg_d_0 = mcGraph.addParticle();
4131 MCParticleGraph::GraphParticle& mcg_d_1 = mcGraph.addParticle();
4132 MCParticleGraph::GraphParticle& mcg_gd_0_0 = mcGraph.addParticle();
4133 MCParticleGraph::GraphParticle& mcg_gd_0_1 = mcGraph.addParticle();
4134 MCParticleGraph::GraphParticle& mcg_ggd_0_0_0 = mcGraph.addParticle();
4135 MCParticleGraph::GraphParticle& mcg_ggd_0_0_1 = mcGraph.addParticle();
4136 MCParticleGraph::GraphParticle& mcg_not_child = mcGraph.addParticle();
4137
4138 mcg_m.setPDG(521);
4139 mcg_d_0.setPDG(-411);
4140 mcg_d_1.setPDG(Const::pion.getPDGCode());
4141 mcg_gd_0_0.setPDG(Const::Kshort.getPDGCode());
4142 mcg_gd_0_1.setPDG(-Const::pion.getPDGCode());
4143 mcg_ggd_0_0_0.setPDG(Const::pion.getPDGCode());
4144 mcg_ggd_0_0_1.setPDG(-Const::pion.getPDGCode());
4145 mcg_not_child.setPDG(Const::pion.getPDGCode());
4146
4147 mcg_d_0.comesFrom(mcg_m);
4148 mcg_d_1.comesFrom(mcg_m);
4149 mcg_gd_0_0.comesFrom(mcg_d_0);
4150 mcg_gd_0_1.comesFrom(mcg_d_0);
4151 mcg_ggd_0_0_0.comesFrom(mcg_gd_0_1);
4152 mcg_ggd_0_0_1.comesFrom(mcg_gd_0_1);
4153
4154 mcGraph.generateList();
4155
4156 // Get MC Particles from StoreArray
4157 auto* mc_m = mcParticles[0];
4158 auto* mc_d_0 = mcParticles[1];
4159 auto* mc_d_1 = mcParticles[2];
4160 auto* mc_gd_0_0 = mcParticles[3];
4161 auto* mc_gd_0_1 = mcParticles[4];
4162 auto* mc_ggd_0_0_0 = mcParticles[5];
4163 auto* mc_ggd_0_0_1 = mcParticles[6];
4164 auto* mc_not_child = mcParticles[7];
4165
4166 mc_m->setStatus(MCParticle::c_PrimaryParticle);
4167 mc_d_0->setStatus(MCParticle::c_PrimaryParticle);
4168 mc_d_1->setStatus(MCParticle::c_PrimaryParticle);
4169 mc_gd_0_0->setStatus(MCParticle::c_PrimaryParticle);
4170 mc_gd_0_1->setStatus(MCParticle::c_PrimaryParticle);
4171 mc_ggd_0_0_0->setStatus(MCParticle::c_PrimaryParticle);
4172 mc_ggd_0_0_1->setStatus(MCParticle::c_PrimaryParticle);
4173 mc_not_child->setStatus(MCParticle::c_PrimaryParticle);
4174
4175 // Creation of D decay: D->K0s(->pi pi) K0s(->pi pi) (not matched)
4176
4177 const Particle* D_gd_0_0 = particles.appendNew(PxPyPzEVector(0.0, 1, 1, 1), 211);
4178 const Particle* D_gd_0_1 = particles.appendNew(PxPyPzEVector(1.0, 1, 1, 1), -211);
4179 const Particle* D_gd_1_0 = particles.appendNew(PxPyPzEVector(2.0, 1, 1, 1), 211);
4180 const Particle* D_gd_1_1 = particles.appendNew(PxPyPzEVector(3.0, 1, 1, 1), -211);
4181
4182 D_grandDaughterIndices_0.push_back(D_gd_0_0->getArrayIndex());
4183 D_grandDaughterIndices_0.push_back(D_gd_0_1->getArrayIndex());
4184 D_grandDaughterIndices_1.push_back(D_gd_1_0->getArrayIndex());
4185 D_grandDaughterIndices_1.push_back(D_gd_1_1->getArrayIndex());
4186 momentum_0 = D_gd_0_0->get4Vector() + D_gd_0_1->get4Vector();
4187 momentum_1 = D_gd_1_0->get4Vector() + D_gd_1_1->get4Vector();
4188
4189
4190 const Particle* D_d_0 = particles.appendNew(momentum_0, 310, Particle::c_Unflavored, D_grandDaughterIndices_0);
4191 const Particle* D_d_1 = particles.appendNew(momentum_1, 310, Particle::c_Unflavored, D_grandDaughterIndices_1);
4192
4193
4194 momentum = D_d_0->get4Vector() + D_d_1->get4Vector();
4195 D_daughterIndices.push_back(D_d_0->getArrayIndex());
4196 D_daughterIndices.push_back(D_d_1->getArrayIndex());
4197
4198 const Particle* D_m = particles.appendNew(momentum, 421, Particle::c_Unflavored, D_daughterIndices);
4199 DList->addParticle(D_m);
4200
4201 // Creating B decay
4202 const Particle* d_1 = particles.appendNew(PxPyPzEVector(0.0, 1, 1, 1), 211);
4203 const Particle* gd_0_1 = particles.appendNew(PxPyPzEVector(1.0, 1, 1, 1), -211);
4204 const Particle* ggd_0_0_0 = particles.appendNew(PxPyPzEVector(2.0, 1, 1, 1), 211);
4205 const Particle* ggd_0_0_1 = particles.appendNew(PxPyPzEVector(3.0, 1, 1, 1), -211);
4206
4207 grandGrandDaughterIndices.push_back(ggd_0_0_0->getArrayIndex());
4208 grandGrandDaughterIndices.push_back(ggd_0_0_1->getArrayIndex());
4209 momentum_0 = ggd_0_0_0->get4Vector() + ggd_0_0_1->get4Vector();
4210 const Particle* gd_0_0 = particles.appendNew(momentum_0, 310, Particle::c_Unflavored, grandGrandDaughterIndices);
4211
4212 grandDaughterIndices.push_back(gd_0_0->getArrayIndex());
4213 grandDaughterIndices.push_back(gd_0_1->getArrayIndex());
4214 momentum_1 = gd_0_0->get4Vector() + gd_0_1->get4Vector();
4215 const Particle* d_0 = particles.appendNew(momentum_1, -411, Particle::c_Unflavored, grandDaughterIndices);
4216
4217 daughterIndices.push_back(d_0->getArrayIndex());
4218 daughterIndices.push_back(d_1->getArrayIndex());
4219 momentum = d_0->get4Vector() + d_1->get4Vector();
4220 const Particle* m = particles.appendNew(momentum, 521, Particle::c_Unflavored, daughterIndices);
4221 BList->addParticle(m);
4222
4223 // Particle that is not an child
4224 const Particle* not_child = particles.appendNew(PxPyPzEVector(5.0, 1, 1, 1), 211);
4225
4226 // Particle that is not an child and doesn't have MC particle
4227 const Particle* not_child_2 = particles.appendNew(PxPyPzEVector(6.0, 1, 1, 1), 211);
4228
4229 gd_0_0->addRelationTo(mc_gd_0_0);
4230 gd_0_1->addRelationTo(mc_gd_0_1);
4231 ggd_0_0_0->addRelationTo(mc_ggd_0_0_0);
4232 ggd_0_0_1->addRelationTo(mc_ggd_0_0_1);
4233 d_0->addRelationTo(mc_d_0);
4234 d_1->addRelationTo(mc_d_1);
4235 m->addRelationTo(mc_m);
4236 not_child->addRelationTo(mc_not_child);
4237
4238 const Manager::Var* var_0 = Manager::Instance().getVariable("isMCDescendantOfList(B:vartest)");
4239 ASSERT_NE(var_0, nullptr);
4240 EXPECT_FALSE(std::get<bool>(var_0->function(D_gd_0_0)));
4241 EXPECT_FALSE(std::get<bool>(var_0->function(D_gd_0_1)));
4242 EXPECT_FALSE(std::get<bool>(var_0->function(D_gd_1_0)));
4243 EXPECT_FALSE(std::get<bool>(var_0->function(D_gd_1_1)));
4244 EXPECT_FALSE(std::get<bool>(var_0->function(D_d_0)));
4245 EXPECT_FALSE(std::get<bool>(var_0->function(D_d_1)));
4246 EXPECT_TRUE(std::get<bool>(var_0->function(ggd_0_0_0)));
4247 EXPECT_TRUE(std::get<bool>(var_0->function(ggd_0_0_1)));
4248 EXPECT_TRUE(std::get<bool>(var_0->function(gd_0_0)));
4249 EXPECT_TRUE(std::get<bool>(var_0->function(gd_0_1)));
4250 EXPECT_TRUE(std::get<bool>(var_0->function(d_0)));
4251 EXPECT_TRUE(std::get<bool>(var_0->function(d_1)));
4252 EXPECT_FALSE(std::get<bool>(var_0->function(not_child)));
4253 EXPECT_FALSE(std::get<bool>(var_0->function(not_child_2)));
4254
4255 const Manager::Var* var_1 = Manager::Instance().getVariable("isMCDescendantOfList(B:vartest, D0:vartest)");
4256 ASSERT_NE(var_1, nullptr);
4257 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_0_0)));
4258 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_0_1)));
4259 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_1_0)));
4260 EXPECT_FALSE(std::get<bool>(var_1->function(D_gd_1_1)));
4261 EXPECT_FALSE(std::get<bool>(var_1->function(D_d_0)));
4262 EXPECT_FALSE(std::get<bool>(var_1->function(D_d_1)));
4263 EXPECT_TRUE(std::get<bool>(var_1->function(ggd_0_0_0)));
4264 EXPECT_TRUE(std::get<bool>(var_1->function(ggd_0_0_1)));
4265 EXPECT_TRUE(std::get<bool>(var_1->function(gd_0_0)));
4266 EXPECT_TRUE(std::get<bool>(var_1->function(gd_0_1)));
4267 EXPECT_TRUE(std::get<bool>(var_1->function(d_0)));
4268 EXPECT_TRUE(std::get<bool>(var_1->function(d_1)));
4269 EXPECT_FALSE(std::get<bool>(var_1->function(not_child)));
4270 EXPECT_FALSE(std::get<bool>(var_1->function(not_child_2)));
4271
4272 const Manager::Var* var_2 = Manager::Instance().getVariable("isMCDescendantOfList(B:vartest, -1)");
4273 ASSERT_NE(var_2, nullptr);
4274 EXPECT_FALSE(std::get<bool>(var_2->function(D_gd_0_0)));
4275 EXPECT_FALSE(std::get<bool>(var_2->function(D_gd_0_1)));
4276 EXPECT_FALSE(std::get<bool>(var_2->function(D_gd_1_0)));
4277 EXPECT_FALSE(std::get<bool>(var_2->function(D_gd_1_1)));
4278 EXPECT_FALSE(std::get<bool>(var_2->function(D_d_0)));
4279 EXPECT_FALSE(std::get<bool>(var_2->function(D_d_1)));
4280 EXPECT_TRUE(std::get<bool>(var_2->function(ggd_0_0_0)));
4281 EXPECT_TRUE(std::get<bool>(var_2->function(ggd_0_0_1)));
4282 EXPECT_TRUE(std::get<bool>(var_2->function(gd_0_0)));
4283 EXPECT_TRUE(std::get<bool>(var_2->function(gd_0_1)));
4284 EXPECT_TRUE(std::get<bool>(var_2->function(d_0)));
4285 EXPECT_TRUE(std::get<bool>(var_2->function(d_1)));
4286 EXPECT_FALSE(std::get<bool>(var_2->function(not_child)));
4287 EXPECT_FALSE(std::get<bool>(var_2->function(not_child_2)));
4288
4289 const Manager::Var* var_3 = Manager::Instance().getVariable("isMCDescendantOfList(B:vartest, 1)");
4290 ASSERT_NE(var_3, nullptr);
4291 EXPECT_FALSE(std::get<bool>(var_3->function(D_gd_0_0)));
4292 EXPECT_FALSE(std::get<bool>(var_3->function(D_gd_0_1)));
4293 EXPECT_FALSE(std::get<bool>(var_3->function(D_gd_1_0)));
4294 EXPECT_FALSE(std::get<bool>(var_3->function(D_gd_1_1)));
4295 EXPECT_FALSE(std::get<bool>(var_3->function(D_d_0)));
4296 EXPECT_FALSE(std::get<bool>(var_3->function(D_d_1)));
4297 EXPECT_FALSE(std::get<bool>(var_3->function(ggd_0_0_0)));
4298 EXPECT_FALSE(std::get<bool>(var_3->function(ggd_0_0_1)));
4299 EXPECT_FALSE(std::get<bool>(var_3->function(gd_0_0)));
4300 EXPECT_FALSE(std::get<bool>(var_3->function(gd_0_1)));
4301 EXPECT_TRUE(std::get<bool>(var_3->function(d_0)));
4302 EXPECT_TRUE(std::get<bool>(var_3->function(d_1)));
4303 EXPECT_FALSE(std::get<bool>(var_3->function(not_child)));
4304 EXPECT_FALSE(std::get<bool>(var_3->function(not_child_2)));
4305
4306 const Manager::Var* var_4 = Manager::Instance().getVariable("isMCDescendantOfList(B:vartest, 2)");
4307 ASSERT_NE(var_4, nullptr);
4308 EXPECT_FALSE(std::get<bool>(var_4->function(D_gd_0_0)));
4309 EXPECT_FALSE(std::get<bool>(var_4->function(D_gd_0_1)));
4310 EXPECT_FALSE(std::get<bool>(var_4->function(D_gd_1_0)));
4311 EXPECT_FALSE(std::get<bool>(var_4->function(D_gd_1_1)));
4312 EXPECT_FALSE(std::get<bool>(var_4->function(D_d_0)));
4313 EXPECT_FALSE(std::get<bool>(var_4->function(D_d_1)));
4314 EXPECT_FALSE(std::get<bool>(var_4->function(ggd_0_0_0)));
4315 EXPECT_FALSE(std::get<bool>(var_4->function(ggd_0_0_1)));
4316 EXPECT_TRUE(std::get<bool>(var_4->function(gd_0_0)));
4317 EXPECT_TRUE(std::get<bool>(var_4->function(gd_0_1)));
4318 EXPECT_FALSE(std::get<bool>(var_4->function(d_0)));
4319 EXPECT_FALSE(std::get<bool>(var_4->function(d_1)));
4320 EXPECT_FALSE(std::get<bool>(var_4->function(not_child)));
4321 EXPECT_FALSE(std::get<bool>(var_4->function(not_child_2)));
4322
4323
4324 const Manager::Var* var_5 = Manager::Instance().getVariable("isMCDescendantOfList(B:vartest, 3)");
4325 ASSERT_NE(var_5, nullptr);
4326 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_0_0)));
4327 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_0_1)));
4328 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_1_0)));
4329 EXPECT_FALSE(std::get<bool>(var_5->function(D_gd_1_1)));
4330 EXPECT_FALSE(std::get<bool>(var_5->function(D_d_0)));
4331 EXPECT_FALSE(std::get<bool>(var_5->function(D_d_1)));
4332 EXPECT_TRUE(std::get<bool>(var_5->function(ggd_0_0_0)));
4333 EXPECT_TRUE(std::get<bool>(var_5->function(ggd_0_0_1)));
4334 EXPECT_FALSE(std::get<bool>(var_5->function(gd_0_0)));
4335 EXPECT_FALSE(std::get<bool>(var_5->function(gd_0_1)));
4336 EXPECT_FALSE(std::get<bool>(var_5->function(d_0)));
4337 EXPECT_FALSE(std::get<bool>(var_5->function(d_1)));
4338 EXPECT_FALSE(std::get<bool>(var_5->function(not_child)));
4339 EXPECT_FALSE(std::get<bool>(var_5->function(not_child_2)));
4340 }
4341
4342
4343
4344
4345
4346 class PIDVariableTest : public ::testing::Test {
4347 protected:
4349 void SetUp() override
4350 {
4354 StoreArray<MCParticle> mcparticles;
4355 StoreArray<PIDLikelihood> likelihood;
4356 StoreArray<Particle> particles;
4357 StoreArray<Track> tracks;
4358 peim.registerInDataStore();
4359 tfrs.registerInDataStore();
4360 mcparticles.registerInDataStore();
4361 likelihood.registerInDataStore();
4362 particles.registerInDataStore();
4363 tracks.registerInDataStore();
4364 particles.registerRelationTo(likelihood);
4365 tracks.registerRelationTo(likelihood);
4367 }
4368
4370 void TearDown() override
4371 {
4373 }
4374 };
4375
4376 TEST_F(PIDVariableTest, LogLikelihood)
4377 {
4378 StoreArray<PIDLikelihood> likelihood;
4379 StoreArray<Particle> particles;
4380 StoreArray<Track> tracks;
4382
4383 // create tracks and trackFitResutls
4384 TRandom3 generator;
4385 const float pValue = 0.5;
4386 const float bField = 1.5;
4387 const int charge = 1;
4388 TMatrixDSym cov6(6);
4389 // Generate a random put orthogonal pair of vectors in the r-phi plane
4390 ROOT::Math::Cartesian2D d(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
4391 ROOT::Math::Cartesian2D pt(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
4392 d.SetXY(d.X(), -(d.X()*pt.X()) / pt.Y());
4393 // Add a random z component
4394 ROOT::Math::XYZVector position(d.X(), d.Y(), generator.Uniform(-1, 1));
4395 ROOT::Math::XYZVector momentum(pt.X(), pt.Y(), generator.Uniform(-1, 1));
4396
4397 auto CDCValue = static_cast<unsigned long long int>(0x300000000000000);
4398 tfrs.appendNew(position, momentum, cov6, charge, Const::electron, pValue, bField, CDCValue, 16777215, 0);
4399 Track mytrack;
4401 Track* allTrack = tracks.appendNew(mytrack);
4402 Track* noSVDTrack = tracks.appendNew(mytrack);
4403 Track* noPIDTrack = tracks.appendNew(mytrack);
4404 Track* dEdxTrack = tracks.appendNew(mytrack);
4405
4406 // Fill by hand likelihood values for all the detectors and hypothesis
4407 // This is clearly not a physical case, since a particle cannot leave good
4408 // signals in both TOP and ARICH
4409 auto* lAll = likelihood.appendNew();
4410 lAll->setLogLikelihood(Const::TOP, Const::electron, 0.18);
4411 lAll->setLogLikelihood(Const::ARICH, Const::electron, 0.16);
4412 lAll->setLogLikelihood(Const::ECL, Const::electron, 0.14);
4413 lAll->setLogLikelihood(Const::CDC, Const::electron, 0.12);
4414 lAll->setLogLikelihood(Const::SVD, Const::electron, 0.1);
4415 lAll->setLogLikelihood(Const::KLM, Const::electron, 0.01);
4416
4417 lAll->setLogLikelihood(Const::TOP, Const::muon, 0.5);
4418 lAll->setLogLikelihood(Const::ARICH, Const::muon, 0.52);
4419 lAll->setLogLikelihood(Const::ECL, Const::muon, 0.54);
4420 lAll->setLogLikelihood(Const::CDC, Const::muon, 0.56);
4421 lAll->setLogLikelihood(Const::SVD, Const::muon, 0.58);
4422 lAll->setLogLikelihood(Const::KLM, Const::muon, 0.8);
4423
4424 lAll->setLogLikelihood(Const::TOP, Const::pion, 0.2);
4425 lAll->setLogLikelihood(Const::ARICH, Const::pion, 0.22);
4426 lAll->setLogLikelihood(Const::ECL, Const::pion, 0.24);
4427 lAll->setLogLikelihood(Const::CDC, Const::pion, 0.26);
4428 lAll->setLogLikelihood(Const::SVD, Const::pion, 0.28);
4429 lAll->setLogLikelihood(Const::KLM, Const::pion, 0.2);
4430
4431 lAll->setLogLikelihood(Const::TOP, Const::kaon, 0.3);
4432 lAll->setLogLikelihood(Const::ARICH, Const::kaon, 0.32);
4433 lAll->setLogLikelihood(Const::ECL, Const::kaon, 0.34);
4434 lAll->setLogLikelihood(Const::CDC, Const::kaon, 0.36);
4435 lAll->setLogLikelihood(Const::SVD, Const::kaon, 0.38);
4436 lAll->setLogLikelihood(Const::KLM, Const::kaon, 0.2);
4437
4438 lAll->setLogLikelihood(Const::TOP, Const::proton, 0.4);
4439 lAll->setLogLikelihood(Const::ARICH, Const::proton, 0.42);
4440 lAll->setLogLikelihood(Const::ECL, Const::proton, 0.44);
4441 lAll->setLogLikelihood(Const::CDC, Const::proton, 0.46);
4442 lAll->setLogLikelihood(Const::SVD, Const::proton, 0.48);
4443 lAll->setLogLikelihood(Const::KLM, Const::proton, 0.02);
4444
4445 lAll->setLogLikelihood(Const::TOP, Const::deuteron, 0.6);
4446 lAll->setLogLikelihood(Const::ARICH, Const::deuteron, 0.62);
4447 lAll->setLogLikelihood(Const::ECL, Const::deuteron, 0.64);
4448 lAll->setLogLikelihood(Const::CDC, Const::deuteron, 0.66);
4449 lAll->setLogLikelihood(Const::SVD, Const::deuteron, 0.68);
4450 lAll->setLogLikelihood(Const::KLM, Const::deuteron, 0.02);
4451
4452 // Likelihoods for all detectors but SVD
4453 auto* lAllNoSVD = likelihood.appendNew();
4454
4455 for (const auto& det : Const::PIDDetectorSet::set()) {
4456 for (const auto& hypo : Const::chargedStableSet) {
4457 if (det != Const::SVD) {
4458 lAllNoSVD->setLogLikelihood(det, hypo, lAll->getLogL(hypo, det));
4459 }
4460 }
4461 }
4462
4463 // Likelihoods for a dEdx only case
4464 auto* ldEdx = likelihood.appendNew();
4465 ldEdx->setLogLikelihood(Const::CDC, Const::electron, 0.12);
4466 ldEdx->setLogLikelihood(Const::SVD, Const::electron, 0.1);
4467
4468 ldEdx->setLogLikelihood(Const::CDC, Const::pion, 0.26);
4469 ldEdx->setLogLikelihood(Const::SVD, Const::pion, 0.28);
4470
4471 ldEdx->setLogLikelihood(Const::CDC, Const::kaon, 0.36);
4472 ldEdx->setLogLikelihood(Const::SVD, Const::kaon, 0.38);
4473
4474 ldEdx->setLogLikelihood(Const::CDC, Const::proton, 0.46);
4475 ldEdx->setLogLikelihood(Const::SVD, Const::proton, 0.48);
4476
4477 ldEdx->setLogLikelihood(Const::CDC, Const::muon, 0.56);
4478 ldEdx->setLogLikelihood(Const::SVD, Const::muon, 0.58);
4479
4480 ldEdx->setLogLikelihood(Const::CDC, Const::deuteron, 0.66);
4481 ldEdx->setLogLikelihood(Const::SVD, Const::deuteron, 0.68);
4482
4483 allTrack->addRelationTo(lAll);
4484 noSVDTrack->addRelationTo(lAllNoSVD);
4485 dEdxTrack->addRelationTo(ldEdx);
4486
4487 // Table with the sum(LogL) for several cases
4488 // All dEdx AllNoSVD
4489 // e 0.71 0.22 0.61
4490 // mu 3.5 1.14 2.92
4491 // pi 1.4 0.54 1.12
4492 // k 1.9 0.74 1.52
4493 // p 2.22 0.94 1.74
4494 // d 3.22 1.34 2.54
4495
4496 auto* particleAll = particles.appendNew(allTrack, Const::pion);
4497 auto* particleNoSVD = particles.appendNew(noSVDTrack, Const::pion);
4498 auto* particledEdx = particles.appendNew(dEdxTrack, Const::pion);
4499 auto* particleNoID = particles.appendNew(noPIDTrack, Const::pion);
4500
4501 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);
4502 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);
4503
4504 // Basic PID quantities. Currently just wrappers for global probability.
4505 EXPECT_FLOAT_EQ(electronID(particleAll), std::exp(0.71) / numsumexp);
4506 EXPECT_FLOAT_EQ(muonID(particleAll), std::exp(3.5) / numsumexp);
4507 EXPECT_FLOAT_EQ(pionID(particleAll), std::exp(1.4) / numsumexp);
4508 EXPECT_FLOAT_EQ(kaonID(particleAll), std::exp(1.9) / numsumexp);
4509 EXPECT_FLOAT_EQ(protonID(particleAll), std::exp(2.22) / numsumexp);
4510 EXPECT_FLOAT_EQ(deuteronID(particleAll), std::exp(3.22) / numsumexp);
4511
4512 // smart PID that takes the hypothesis into account
4513 auto* particleElectron = particles.appendNew(allTrack, Const::electron);
4514 auto* particleMuon = particles.appendNew(allTrack, Const::muon);
4515 auto* particleKaon = particles.appendNew(allTrack, Const::kaon);
4516 auto* particleProton = particles.appendNew(allTrack, Const::proton);
4517 auto* particleDeuteron = particles.appendNew(allTrack, Const::deuteron);
4518
4519 EXPECT_FLOAT_EQ(particleID(particleAll), std::exp(1.4) / numsumexp); // there's already a pion
4520 EXPECT_FLOAT_EQ(particleID(particleElectron), std::exp(0.71) / numsumexp);
4521 EXPECT_FLOAT_EQ(particleID(particleMuon), std::exp(3.5) / numsumexp);
4522 EXPECT_FLOAT_EQ(particleID(particleKaon), std::exp(1.9) / numsumexp);
4523 EXPECT_FLOAT_EQ(particleID(particleProton), std::exp(2.22) / numsumexp);
4524 EXPECT_FLOAT_EQ(particleID(particleDeuteron), std::exp(3.22) / numsumexp);
4525
4526 // TEMP: PID w/o the SVD.
4527 EXPECT_FLOAT_EQ(electronID_noSVD(particleNoSVD), std::exp(0.61) / numsumexp_noSVD);
4528 EXPECT_FLOAT_EQ(muonID_noSVD(particleNoSVD), std::exp(2.92) / numsumexp_noSVD);
4529 EXPECT_FLOAT_EQ(pionID_noSVD(particleNoSVD), std::exp(1.12) / numsumexp_noSVD);
4530 EXPECT_FLOAT_EQ(kaonID_noSVD(particleNoSVD), std::exp(1.52) / numsumexp_noSVD);
4531 EXPECT_FLOAT_EQ(protonID_noSVD(particleNoSVD), std::exp(1.74) / numsumexp_noSVD);
4532 EXPECT_FLOAT_EQ(deuteronID_noSVD(particleNoSVD), std::exp(2.54) / numsumexp_noSVD);
4533
4534 // Binary PID
4535 std::vector<double> v_pi_K {211., 321.};
4536 std::vector<double> v_pi_p {211., 2212.};
4537 std::vector<double> v_K_p {321., 2212.};
4538 EXPECT_FLOAT_EQ(binaryPID(particleAll, v_pi_K), std::exp(1.4) / (std::exp(1.4) + std::exp(1.9)));
4539 EXPECT_FLOAT_EQ(binaryPID(particleAll, v_pi_p), std::exp(1.4) / (std::exp(1.4) + std::exp(2.22)));
4540 EXPECT_FLOAT_EQ(binaryPID(particleAll, v_K_p), std::exp(1.9) / (std::exp(1.9) + std::exp(2.22)));
4541
4542 // Check what happens if no Likelihood is available
4543 EXPECT_TRUE(std::isnan(electronID(particleNoID)));
4544 EXPECT_TRUE(std::isnan(muonID(particleNoID)));
4545 EXPECT_TRUE(std::isnan(pionID(particleNoID)));
4546 EXPECT_TRUE(std::isnan(kaonID(particleNoID)));
4547 EXPECT_TRUE(std::isnan(protonID(particleNoID)));
4548 EXPECT_TRUE(std::isnan(deuteronID(particleNoID)));
4549
4550 //expert stuff: LogL values
4551 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidLogLikelihoodValueExpert(11, TOP)")->function(particleAll)),
4552 0.18);
4553 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidLogLikelihoodValueExpert(11, ALL)")->function(particleAll)),
4554 0.71);
4555 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidLogLikelihoodValueExpert(2212, TOP, CDC)")->function(
4556 particleAll)), 0.86);
4557
4558 // global probability
4559 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(1000010020, ALL)")->function(particleAll)),
4560 std::exp(3.22) / numsumexp);
4561 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(2212, ALL)")->function(particleAll)),
4562 std::exp(2.22) / numsumexp);
4563 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(211, ALL)")->function(particleAll)),
4564 std::exp(1.4) / numsumexp);
4565 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(321, ALL)")->function(particleAll)),
4566 std::exp(1.9) / numsumexp);
4567 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(13, ALL)")->function(particleAll)),
4568 std::exp(3.5) / numsumexp);
4569 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(11, ALL)")->function(particleAll)),
4570 std::exp(0.71) / numsumexp);
4571 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(211, ALL)")->function(particledEdx)),
4572 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)));
4573 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(211, ALL)")->function(particledEdx)),
4574 std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(211, CDC, SVD)")->function(particleAll)));
4575 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(211, CDC)")->function(particledEdx)),
4576 std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(211, CDC)")->function(particleAll)));
4577 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(321, CDC)")->function(particleAll)),
4578 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)));
4579
4580 // binary probability
4581 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(321, 2212, ALL)")->function(
4582 particleAll)),
4583 1.0 / (1.0 + std::exp(2.22 - 1.9)));
4584 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(321, 2212, ALL)")->function(
4585 particledEdx)),
4586 1.0 / (1.0 + std::exp(0.94 - 0.74)));
4587 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(321, 2212, CDC, SVD)")->function(
4588 particleAll)),
4589 1.0 / (1.0 + std::exp(0.94 - 0.74)));
4590
4591 // No likelihood available
4592 EXPECT_TRUE(std::isnan(std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(321, 2212, KLM)")->function(
4593 particledEdx))));
4594 EXPECT_TRUE(std::isnan(std::get<double>(Manager::Instance().getVariable("pidLogLikelihoodValueExpert(11, TOP, CDC, SVD)")->function(
4595 particleNoID))));
4596 EXPECT_TRUE(std::isnan(std::get<double>(Manager::Instance().getVariable("pidLogLikelihoodValueExpert(11, TOP)")->function(
4597 particledEdx))));
4598 EXPECT_TRUE(std::isnan(std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(321, 2212, KLM)")->function(
4599 particledEdx))));
4600 EXPECT_TRUE(std::isnan(std::get<double>
4601 (Manager::Instance().getVariable("pidPairProbabilityExpert(321, 2212, ECL, TOP, ARICH)")->function(
4602 particledEdx))));
4603 EXPECT_FALSE(std::isnan(std::get<double>
4604 (Manager::Instance().getVariable("pidPairProbabilityExpert(321, 2212, ECL, TOP, ARICH, SVD)")->function(
4605 particledEdx))));
4606 //Mostlikely PDG tests:
4607 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidMostLikelyPDG()")->function(particledEdx)), 1.00001e+09);
4608 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidMostLikelyPDG(0.5, 0.1, 0.1, 0.1, 0.1, 0.1)")->function(
4609 particledEdx)),
4610 Const::electron.getPDGCode());
4611 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidMostLikelyPDG(0.1, 0.5, 0.1, 0.1, 0.1, 0.1)")->function(
4612 particledEdx)),
4613 Const::muon.getPDGCode());
4614 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidMostLikelyPDG(0.1, 0.1, 0.5, 0.1, 0.1, 0.1)")->function(
4615 particledEdx)),
4616 Const::pion.getPDGCode());
4617 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidMostLikelyPDG(0.1, 0.1, 0.1, 0.5, 0.1, 0.1)")->function(
4618 particledEdx)),
4619 Const::kaon.getPDGCode());
4620 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidMostLikelyPDG(0.1, 0.1, 0.1, 0.1, 0.5, 0.1)")->function(
4621 particledEdx)),
4622 Const::proton.getPDGCode());
4623 EXPECT_FLOAT_EQ(std::get<double>(Manager::Instance().getVariable("pidMostLikelyPDG(0, 1., 0, 0, 0, 0)")->function(particledEdx)),
4624 Const::muon.getPDGCode());
4625 }
4626
4627 TEST_F(PIDVariableTest, MissingLikelihood)
4628 {
4629 StoreArray<PIDLikelihood> likelihood;
4630 StoreArray<Particle> particles;
4631 StoreArray<Track> tracks;
4633
4634 // create tracks and trackFitResutls
4635 TRandom3 generator;
4636 const float pValue = 0.5;
4637 const float bField = 1.5;
4638 const int charge = 1;
4639 TMatrixDSym cov6(6);
4640 // Generate a random put orthogonal pair of vectors in the r-phi plane
4641 ROOT::Math::Cartesian2D d(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
4642 ROOT::Math::Cartesian2D pt(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
4643 d.SetXY(d.X(), -(d.X()*pt.X()) / pt.Y());
4644 // Add a random z component
4645 ROOT::Math::XYZVector position(d.X(), d.Y(), generator.Uniform(-1, 1));
4646 ROOT::Math::XYZVector momentum(pt.X(), pt.Y(), generator.Uniform(-1, 1));
4647
4648 auto CDCValue = static_cast<unsigned long long int>(0x300000000000000);
4649 tfrs.appendNew(position, momentum, cov6, charge, Const::electron, pValue, bField, CDCValue, 16777215, 0);
4650 Track mytrack;
4652 Track* savedTrack1 = tracks.appendNew(mytrack);
4653 Track* savedTrack2 = tracks.appendNew(mytrack);
4654 Track* savedTrack3 = tracks.appendNew(mytrack);
4655 Track* savedTrack4 = tracks.appendNew(mytrack);
4656
4657 auto* l1 = likelihood.appendNew();
4658 l1->setLogLikelihood(Const::TOP, Const::electron, 0.18);
4659 l1->setLogLikelihood(Const::ECL, Const::electron, 0.14);
4660 savedTrack1->addRelationTo(l1);
4661
4662 auto* electron = particles.appendNew(savedTrack1, Const::electron);
4663
4664 auto* l2 = likelihood.appendNew();
4665 l2->setLogLikelihood(Const::TOP, Const::pion, 0.2);
4666 l2->setLogLikelihood(Const::ARICH, Const::pion, 0.22);
4667 l2->setLogLikelihood(Const::ECL, Const::pion, 0.24);
4668 l2->setLogLikelihood(Const::CDC, Const::pion, 0.26);
4669 l2->setLogLikelihood(Const::SVD, Const::pion, 0.28);
4670 savedTrack2->addRelationTo(l2);
4671
4672 auto* pion = particles.appendNew(savedTrack2, Const::pion);
4673
4674 auto* l3 = likelihood.appendNew();
4675 l3->setLogLikelihood(Const::TOP, Const::kaon, 0.3);
4676 l3->setLogLikelihood(Const::ARICH, Const::kaon, 0.32);
4677 savedTrack3->addRelationTo(l3);
4678
4679 auto* kaon = particles.appendNew(savedTrack3, Const::kaon);
4680
4681 auto* l4 = likelihood.appendNew();
4682 l4->setLogLikelihood(Const::ARICH, Const::proton, 0.42);
4683 l4->setLogLikelihood(Const::ECL, Const::proton, 0.44);
4684 l4->setLogLikelihood(Const::CDC, Const::proton, 0.46);
4685 l4->setLogLikelihood(Const::SVD, Const::proton, 0.48);
4686 savedTrack4->addRelationTo(l4);
4687
4688 auto* proton = particles.appendNew(savedTrack4, Const::proton);
4689
4690 const Manager::Var* varMissECL = Manager::Instance().getVariable("pidMissingProbabilityExpert(ECL)");
4691 const Manager::Var* varMissTOP = Manager::Instance().getVariable("pidMissingProbabilityExpert(TOP)");
4692 const Manager::Var* varMissARICH = Manager::Instance().getVariable("pidMissingProbabilityExpert(ARICH)");
4693
4694
4695 EXPECT_FLOAT_EQ(std::get<double>(varMissTOP->function(electron)), 0.0);
4696 EXPECT_FLOAT_EQ(std::get<double>(varMissTOP->function(pion)), 0.0);
4697 EXPECT_FLOAT_EQ(std::get<double>(varMissTOP->function(kaon)), 0.0);
4698 EXPECT_FLOAT_EQ(std::get<double>(varMissTOP->function(proton)), 1.0);
4699
4700 EXPECT_FLOAT_EQ(std::get<double>(varMissARICH->function(electron)), 1.0);
4701 EXPECT_FLOAT_EQ(std::get<double>(varMissARICH->function(pion)), 0.0);
4702 EXPECT_FLOAT_EQ(std::get<double>(varMissARICH->function(kaon)), 0.0);
4703 EXPECT_FLOAT_EQ(std::get<double>(varMissARICH->function(proton)), 0.0);
4704
4705 EXPECT_FLOAT_EQ(std::get<double>(varMissECL->function(electron)), 0.0);
4706 EXPECT_FLOAT_EQ(std::get<double>(varMissECL->function(pion)), 0.0);
4707 EXPECT_FLOAT_EQ(std::get<double>(varMissECL->function(kaon)), 1.0);
4708 EXPECT_FLOAT_EQ(std::get<double>(varMissECL->function(proton)), 0.0);
4709 }
4710
4711 class FlightInfoTest : public ::testing::Test {
4712 protected:
4714 void SetUp() override
4715 {
4719 StoreArray<MCParticle> mcParticles;
4720 StoreArray<Particle> particles;
4721 particles.registerRelationTo(mcParticles);
4724
4725
4726 // Insert MC particle logic here
4727 MCParticle mcKs;
4728 mcKs.setPDG(Const::Kshort.getPDGCode());
4729 mcKs.setProductionVertex(1.0, 1.0, 0.0);
4730 mcKs.setDecayVertex(4.0, 5.0, 0.0);
4731 mcKs.setProductionTime(0);
4732 mcKs.setMassFromPDG();
4733 mcKs.setMomentum(1.164, 1.55200, 0);
4734 float decayTime = 5 * mcKs.getMass() / mcKs.getEnergy();
4735 mcKs.setDecayTime(decayTime);
4737 MCParticle* newMCKs = mcParticles.appendNew(mcKs);
4738
4739
4740
4741 MCParticle mcDp;
4742 mcDp.setPDG(411);
4743 mcDp.setDecayVertex(1.0, 1.0, 0.0);
4744 mcDp.setMassFromPDG();
4746 MCParticle* newMCDp = mcParticles.appendNew(mcDp);
4747
4748 // Insert Reco particle logic here
4749 PxPyPzEVector momentum;
4750 TMatrixFSym error(7);
4751 error.Zero();
4752 error(0, 0) = 0.05;
4753 error(1, 1) = 0.2;
4754 error(2, 2) = 0.4;
4755 error(3, 3) = 0.01;
4756 error(4, 4) = 0.04;
4757 error(5, 5) = 0.00875;
4758 error(6, 6) = 0.01;
4759 Particle pi(PxPyPzEVector(1.59607, 1.19705, 0, 2), 211);
4760 momentum += pi.get4Vector();
4761 Particle* newpi = particles.appendNew(pi);
4762
4763
4764 Particle Ks(PxPyPzEVector(1.164, 1.55200, 0, 2), 310, Particle::c_Unflavored, Particle::c_Composite, 0);
4765 Ks.setVertex(XYZVector(4.0, 5.0, 0.0));
4766 Ks.setMomentumVertexErrorMatrix(error); // (order: px,py,pz,E,x,y,z)
4767 momentum += Ks.get4Vector();
4768 Ks.addExtraInfo("prodVertX", 1.0);
4769 Ks.addExtraInfo("prodVertY", 1.0);
4770 Ks.addExtraInfo("prodVertZ", 0.0);
4771 Ks.addExtraInfo("prodVertSxx", 0.04);
4772 Ks.addExtraInfo("prodVertSxy", 0.0);
4773 Ks.addExtraInfo("prodVertSxz", 0.0);
4774 Ks.addExtraInfo("prodVertSyx", 0.0);
4775 Ks.addExtraInfo("prodVertSyy", 0.00875);
4776 Ks.addExtraInfo("prodVertSyz", 0.0);
4777 Ks.addExtraInfo("prodVertSzx", 0.0);
4778 Ks.addExtraInfo("prodVertSzy", 0.0);
4779 Ks.addExtraInfo("prodVertSzz", 0.01);
4780 Particle* newKs = particles.appendNew(Ks);
4781 newKs->addRelationTo(newMCKs);
4782
4783
4784 Particle Dp(momentum, 411, Particle::c_Flavored, Particle::c_Composite, 0);
4785 Dp.appendDaughter(newpi);
4786 Dp.appendDaughter(newKs);
4787 XYZVector motherVtx(1.0, 1.0, 0.0);
4788 Dp.setVertex(motherVtx);
4789 Dp.setMomentumVertexErrorMatrix(error); // (order: px,py,pz,E,x,y,z)
4790 Dp.addExtraInfo("prodVertX", 0.0);
4791 Dp.addExtraInfo("prodVertY", 1.0);
4792 Dp.addExtraInfo("prodVertZ", -2.0);
4793 Dp.addExtraInfo("prodVertSxx", 0.04);
4794 Dp.addExtraInfo("prodVertSxy", 0.0);
4795 Dp.addExtraInfo("prodVertSxz", 0.0);
4796 Dp.addExtraInfo("prodVertSyx", 0.0);
4797 Dp.addExtraInfo("prodVertSyy", 0.01);
4798 Dp.addExtraInfo("prodVertSyz", 0.0);
4799 Dp.addExtraInfo("prodVertSzx", 0.0);
4800 Dp.addExtraInfo("prodVertSzy", 0.0);
4801 Dp.addExtraInfo("prodVertSzz", 0.1575);
4802 Particle* newDp = particles.appendNew(Dp);
4803 newDp->addRelationTo(newMCDp);
4804
4805 }
4806
4808 void TearDown() override
4809 {
4811 }
4812 };
4813 TEST_F(FlightInfoTest, flightDistance)
4814 {
4815 StoreArray<Particle> particles{};
4816 const Particle* newKs = particles[1]; // Ks had flight distance of 5 cm
4817
4818 const Manager::Var* var = Manager::Instance().getVariable("flightDistance");
4819 ASSERT_NE(var, nullptr);
4820 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 5.0);
4821 }
4822 TEST_F(FlightInfoTest, flightDistanceErr)
4823 {
4824 StoreArray<Particle> particles{};
4825 const Particle* newKs = particles[1]; // Ks had flight distance of 5 cm
4826
4827 const Manager::Var* var = Manager::Instance().getVariable("flightDistanceErr");
4828 ASSERT_NE(var, nullptr);
4829 EXPECT_GT(std::get<double>(var->function(newKs)), 0.0);
4830 }
4831 TEST_F(FlightInfoTest, flightTime)
4832 {
4833 StoreArray<Particle> particles{};
4834 const Particle* newKs = particles[1]; // Ks had flight time of 0.0427 us (t = d/c * m/p)
4835
4836 const Manager::Var* var = Manager::Instance().getVariable("flightTime");
4837 ASSERT_NE(var, nullptr);
4838 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 5.0 / Const::speedOfLight * newKs->getPDGMass() / newKs->getP());
4839 }
4840
4841 TEST_F(FlightInfoTest, flightTimeErr)
4842 {
4843 StoreArray<Particle> particles{};
4844 const Particle* newKs = particles[1]; // Ks should have positive flight distance uncertainty
4845
4846 const Manager::Var* var = Manager::Instance().getVariable("flightTimeErr");
4847 ASSERT_NE(var, nullptr);
4848 EXPECT_GT(std::get<double>(var->function(newKs)), 0.0);
4849 }
4850
4851 TEST_F(FlightInfoTest, flightDistanceOfDaughter)
4852 {
4853 StoreArray<Particle> particles{};
4854 const Particle* newDp = particles[2]; // Get D+, its daughter Ks had flight distance of 5 cm
4855
4856 const Manager::Var* var = Manager::Instance().getVariable("flightDistanceOfDaughter(1)");
4857 ASSERT_NE(var, nullptr);
4858 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 5.0);
4859
4860 var = Manager::Instance().getVariable("flightDistanceOfDaughter(3)");
4861 ASSERT_NE(var, nullptr);
4862 EXPECT_TRUE(std::isnan(std::get<double>(var->function(newDp))));
4863 }
4864 TEST_F(FlightInfoTest, flightDistanceOfDaughterErr)
4865 {
4866 StoreArray<Particle> particles{};
4867 const Particle* newDp = particles[2]; // Get D+, its daughter Ks should have positive flight distance uncertainty
4868
4869 const Manager::Var* var = Manager::Instance().getVariable("flightDistanceOfDaughterErr(1)");
4870 ASSERT_NE(var, nullptr);
4871 EXPECT_GT(std::get<double>(var->function(newDp)), 0.0);
4872
4873 var = Manager::Instance().getVariable("flightDistanceOfDaughterErr(3)");
4874 ASSERT_NE(var, nullptr);
4875 EXPECT_TRUE(std::isnan(std::get<double>(var->function(newDp))));
4876 }
4877 TEST_F(FlightInfoTest, flightTimeOfDaughter)
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("flightTimeOfDaughter(1)");
4883 ASSERT_NE(var, nullptr);
4884 const Particle* Ks = newDp->getDaughter(1);
4885
4886 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 5.0 / Const::speedOfLight * Ks->getPDGMass() / Ks->getP());
4887
4888 var = Manager::Instance().getVariable("flightTimeOfDaughter(3)");
4889 ASSERT_NE(var, nullptr);
4890 EXPECT_TRUE(std::isnan(std::get<double>(var->function(newDp))));
4891 }
4892 TEST_F(FlightInfoTest, flightTimeOfDaughterErr)
4893 {
4894 StoreArray<Particle> particles{};
4895 const Particle* newDp = particles[2]; // Get D+, its daughter Ks should have positive flight time uncertainty
4896
4897 const Manager::Var* var = Manager::Instance().getVariable("flightTimeOfDaughterErr(1)");
4898 ASSERT_NE(var, nullptr);
4899 EXPECT_GT(std::get<double>(var->function(newDp)), 0.0);
4900
4901 var = Manager::Instance().getVariable("flightTimeOfDaughterErr(3)");
4902 ASSERT_NE(var, nullptr);
4903 EXPECT_TRUE(std::isnan(std::get<double>(var->function(newDp))));
4904 }
4905 TEST_F(FlightInfoTest, mcFlightDistanceOfDaughter)
4906 {
4907 StoreArray<Particle> particles{};
4908 const Particle* newDp = particles[2]; // Get D+, its daughter Ks had flight distance of 5 cm
4909
4910 const Manager::Var* var = Manager::Instance().getVariable("mcFlightDistanceOfDaughter(1)");
4911 ASSERT_NE(var, nullptr);
4912
4913 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 5.0);
4914
4915 var = Manager::Instance().getVariable("mcFlightDistanceOfDaughter(3)");
4916 ASSERT_NE(var, nullptr);
4917 EXPECT_TRUE(std::isnan(std::get<double>(var->function(newDp))));
4918 }
4919 TEST_F(FlightInfoTest, mcFlightTimeOfDaughter)
4920 {
4921 StoreArray<Particle> particles{};
4922 const Particle* newDp = particles[2]; // Get D+, its daughter Ks had flight time of 0.0427 us (t = d/c * m/p)
4923
4924 const Manager::Var* var = Manager::Instance().getVariable("mcFlightTimeOfDaughter(1)");
4925 ASSERT_NE(var, nullptr);
4926 auto* Ks = newDp->getDaughter(1)->getRelatedTo<MCParticle>();
4927 // double p = Ks->getMomentum().Mag();
4928 // EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 5.0 / Const::speedOfLight * Ks->getMass() / p);
4929
4930 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), Ks->getLifetime() / Ks->getEnergy()*Ks->getMass());
4931
4932 var = Manager::Instance().getVariable("mcFlightTimeOfDaughter(3)");
4933 ASSERT_NE(var, nullptr);
4934 EXPECT_TRUE(std::isnan(std::get<double>(var->function(newDp))));
4935 }
4936
4937 TEST_F(FlightInfoTest, vertexDistance)
4938 {
4939 StoreArray<Particle> particles{};
4940 const Particle* newKS = particles[1]; // Get KS, as it has both a production and decay vertex
4941
4942 const Manager::Var* var = Manager::Instance().getVariable("vertexDistance");
4943 ASSERT_NE(var, nullptr);
4944 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKS)), 5.0);
4945 }
4946
4947 TEST_F(FlightInfoTest, vertexDistanceError)
4948 {
4949 StoreArray<Particle> particles{};
4950 const Particle* newKS = particles[1]; // Get KS, as it has both a production and decay vertex
4951
4952 const Manager::Var* var = Manager::Instance().getVariable("vertexDistanceErr");
4953 ASSERT_NE(var, nullptr);
4954 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKS)), 0.2);
4955 }
4956
4957 TEST_F(FlightInfoTest, vertexDistanceSignificance)
4958 {
4959 StoreArray<Particle> particles{};
4960 const Particle* newKS = particles[1]; // Get KS, as it has both a production and decay vertex
4961
4962 const Manager::Var* var = Manager::Instance().getVariable("vertexDistanceSignificance");
4963 ASSERT_NE(var, nullptr);
4964 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKS)), 25);
4965 }
4966
4967 TEST_F(FlightInfoTest, vertexDistanceOfDaughter)
4968 {
4969 StoreArray<Particle> particles{};
4970 const Particle* newDp = particles[2]; // Get D+, its daughter KS has both a production and decay vertex
4971
4972 const Manager::Var* var = Manager::Instance().getVariable("vertexDistanceOfDaughter(1, 0)");
4973 ASSERT_NE(var, nullptr);
4974 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 5.0);
4975
4976 var = Manager::Instance().getVariable("vertexDistanceOfDaughter(1)");
4977 ASSERT_NE(var, nullptr);
4978 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 6.0);
4979
4980 var = Manager::Instance().getVariable("vertexDistanceOfDaughter(2)");
4981 ASSERT_NE(var, nullptr);
4982 EXPECT_TRUE(std::isnan(std::get<double>(var->function(newDp))));
4983 }
4984
4985 TEST_F(FlightInfoTest, vertexDistanceOfDaughterError)
4986 {
4987 StoreArray<Particle> particles{};
4988 const Particle* newDp = particles[2]; // Get D+, its daughter KS has both a production and decay vertex
4989
4990 const Manager::Var* var = Manager::Instance().getVariable("vertexDistanceOfDaughterErr(1, 0)");
4991 ASSERT_NE(var, nullptr);
4992 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 0.2);
4993
4994 var = Manager::Instance().getVariable("vertexDistanceOfDaughterErr(1)");
4995 ASSERT_NE(var, nullptr);
4996 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 0.25);
4997 }
4998
4999 TEST_F(FlightInfoTest, vertexDistanceOfDaughterSignificance)
5000 {
5001 StoreArray<Particle> particles{};
5002 const Particle* newDp = particles[2]; // Get D+, its daughter KS has both a production and decay vertex
5003
5004 const Manager::Var* var = Manager::Instance().getVariable("vertexDistanceOfDaughterSignificance(1, 0)");
5005 ASSERT_NE(var, nullptr);
5006 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 25);
5007
5008 var = Manager::Instance().getVariable("vertexDistanceOfDaughterSignificance(1)");
5009 ASSERT_NE(var, nullptr);
5010 EXPECT_FLOAT_EQ(std::get<double>(var->function(newDp)), 24);
5011 }
5012
5013 class VertexVariablesTest : public ::testing::Test {
5014 protected:
5016 void SetUp() override
5017 {
5021 StoreArray<MCParticle> mcParticles;
5022 StoreArray<Particle> particles;
5023 particles.registerRelationTo(mcParticles);
5026
5027
5028 // Insert MC particle logic here
5029 MCParticle mcKs;
5030 mcKs.setPDG(Const::Kshort.getPDGCode());
5031 mcKs.setDecayVertex(4.0, 5.0, 0.0);
5032 mcKs.setProductionVertex(1.0, 2.0, 3.0);
5033 mcKs.setMassFromPDG();
5034 mcKs.setMomentum(1.164, 1.55200, 0);
5036 MCParticle* newMCKs = mcParticles.appendNew(mcKs);
5037
5038 Particle Ks(PxPyPzEVector(1.164, 1.55200, 0, 2), 310);
5039 Ks.setVertex(XYZVector(4.0, 5.0, 0.0));
5040 Ks.addExtraInfo("prodVertX", 1.0);
5041 Ks.addExtraInfo("prodVertY", 2.0);
5042 Ks.addExtraInfo("prodVertZ", 3.0);
5043 Ks.addExtraInfo("prodVertSxx", 0.1);
5044 Ks.addExtraInfo("prodVertSxy", 0.2);
5045 Ks.addExtraInfo("prodVertSxz", 0.3);
5046 Ks.addExtraInfo("prodVertSyx", 0.4);
5047 Ks.addExtraInfo("prodVertSyy", 0.5);
5048 Ks.addExtraInfo("prodVertSyz", 0.6);
5049 Ks.addExtraInfo("prodVertSzx", 0.7);
5050 Ks.addExtraInfo("prodVertSzy", 0.8);
5051 Ks.addExtraInfo("prodVertSzz", 0.9);
5052 Particle* newKs = particles.appendNew(Ks);
5053 newKs->addRelationTo(newMCKs);
5054 }
5055
5057 void TearDown() override
5058 {
5060 }
5061 };
5062
5063 // MC vertex tests
5064 TEST_F(VertexVariablesTest, mcDecayVertexX)
5065 {
5066 StoreArray<Particle> particles{};
5067 const Particle* newKs = particles[0]; // Ks had truth decay x is 4.0
5068
5069 const Manager::Var* var = Manager::Instance().getVariable("mcDecayVertexX");
5070 ASSERT_NE(var, nullptr);
5071 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 4.0);
5072 }
5073
5074 TEST_F(VertexVariablesTest, mcDecayVertexY)
5075 {
5076 StoreArray<Particle> particles{};
5077 const Particle* newKs = particles[0]; // Ks had truth decay y is 5.0
5078
5079 const Manager::Var* var = Manager::Instance().getVariable("mcDecayVertexY");
5080 ASSERT_NE(var, nullptr);
5081 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 5.0);
5082 }
5083
5084 TEST_F(VertexVariablesTest, mcDecayVertexZ)
5085 {
5086 StoreArray<Particle> particles{};
5087 const Particle* newKs = particles[0]; // Ks had truth decay z is 0.0
5088
5089 const Manager::Var* var = Manager::Instance().getVariable("mcDecayVertexZ");
5090 ASSERT_NE(var, nullptr);
5091 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.0);
5092 }
5093
5094
5095 TEST_F(VertexVariablesTest, mcDecayVertexFromIPDistance)
5096 {
5097 StoreArray<Particle> particles{};
5098 const Particle* newKs = particles[0]; // Ks had truth distance of sqrt(41)
5099
5100 const Manager::Var* var = Manager::Instance().getVariable("mcDecayVertexFromIPDistance");
5101 ASSERT_NE(var, nullptr);
5102 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), sqrt(4.0 * 4.0 + 5.0 * 5.0));
5103 }
5104
5105 TEST_F(VertexVariablesTest, mcDecayVertexRho)
5106 {
5107 StoreArray<Particle> particles{};
5108 const Particle* newKs = particles[0]; // Ks had truth rho of sqrt(41)
5109
5110 const Manager::Var* var = Manager::Instance().getVariable("mcDecayVertexRho");
5111 ASSERT_NE(var, nullptr);
5112 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), sqrt(4.0 * 4.0 + 5.0 * 5.0));
5113 }
5114
5115 TEST_F(VertexVariablesTest, mcProductionVertexX)
5116 {
5117 StoreArray<Particle> particles{};
5118 const Particle* newKs = particles[0]; // Ks had production vertex x of 1.0 cm
5119
5120 const Manager::Var* var = Manager::Instance().getVariable("mcProductionVertexX");
5121 ASSERT_NE(var, nullptr);
5122 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 1.0);
5123 }
5124
5125 TEST_F(VertexVariablesTest, mcProductionVertexY)
5126 {
5127 StoreArray<Particle> particles{};
5128 const Particle* newKs = particles[0]; // Ks had production vertex y of 2.0 cm
5129
5130 const Manager::Var* var = Manager::Instance().getVariable("mcProductionVertexY");
5131 ASSERT_NE(var, nullptr);
5132 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 2.0);
5133 }
5134
5135 TEST_F(VertexVariablesTest, mcProductionVertexZ)
5136 {
5137 StoreArray<Particle> particles{};
5138 const Particle* newKs = particles[0]; // Ks had production vertex z of 3.0 cm
5139
5140 const Manager::Var* var = Manager::Instance().getVariable("mcProductionVertexZ");
5141 ASSERT_NE(var, nullptr);
5142 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 3.0);
5143 }
5144
5145 // Production position tests
5146
5147 TEST_F(VertexVariablesTest, prodVertexX)
5148 {
5149 StoreArray<Particle> particles{};
5150 const Particle* newKs = particles[0]; // Ks had production vertex x of 1.0 cm
5151
5152 const Manager::Var* var = Manager::Instance().getVariable("prodVertexX");
5153 ASSERT_NE(var, nullptr);
5154 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 1.0);
5155 }
5156 TEST_F(VertexVariablesTest, prodVertexY)
5157 {
5158 StoreArray<Particle> particles{};
5159 const Particle* newKs = particles[0]; // Ks had production vertex y of 2.0 cm
5160
5161 const Manager::Var* var = Manager::Instance().getVariable("prodVertexY");
5162 ASSERT_NE(var, nullptr);
5163 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 2.0);
5164 }
5165 TEST_F(VertexVariablesTest, prodVertexZ)
5166 {
5167 StoreArray<Particle> particles{};
5168 const Particle* newKs = particles[0]; // Ks had production vertex z of 3.0 cm
5169
5170 const Manager::Var* var = Manager::Instance().getVariable("prodVertexZ");
5171 ASSERT_NE(var, nullptr);
5172 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 3.0);
5173 }
5174
5175 // Production Covariance tests
5176
5177 TEST_F(VertexVariablesTest, prodVertexCov)
5178 {
5179 StoreArray<Particle> particles{};
5180 const Particle* newKs = particles[0]; // Ks had production vertex covariance xx of .1 cm
5181
5182 //const Manager::Var* var = Manager::Instance().getVariable("prodVertexCovXX");
5183 const Manager::Var* var = Manager::Instance().getVariable("prodVertexCov(0,0)");
5184 ASSERT_NE(var, nullptr);
5185 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.1);
5186 var = Manager::Instance().getVariable("prodVertexCov(0,1)");
5187 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.2);
5188 var = Manager::Instance().getVariable("prodVertexCov(0,2)");
5189 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.3);
5190 var = Manager::Instance().getVariable("prodVertexCov(1,0)");
5191 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.4);
5192 var = Manager::Instance().getVariable("prodVertexCov(1,1)");
5193 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.5);
5194 var = Manager::Instance().getVariable("prodVertexCov(1,2)");
5195 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.6);
5196 var = Manager::Instance().getVariable("prodVertexCov(2,0)");
5197 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.7);
5198 var = Manager::Instance().getVariable("prodVertexCov(2,1)");
5199 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.8);
5200 var = Manager::Instance().getVariable("prodVertexCov(2,2)");
5201 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), 0.9);
5202 var = Manager::Instance().getVariable("prodVertexXErr");
5203 ASSERT_NE(var, nullptr);
5204 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), sqrt(0.1));
5205 var = Manager::Instance().getVariable("prodVertexYErr");
5206 ASSERT_NE(var, nullptr);
5207 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), sqrt(0.5));
5208 var = Manager::Instance().getVariable("prodVertexZErr");
5209 ASSERT_NE(var, nullptr);
5210 EXPECT_FLOAT_EQ(std::get<double>(var->function(newKs)), sqrt(0.9));
5211 }
5212
5213 // Tests of ContinuumSuppressionVariables
5214
5215 TEST_F(MetaVariableTest, KSFWVariables)
5216 {
5217 // simple tests that do not require the ROE builder nor the CS builder
5218
5219 // check that garbage input throws helpful B2FATAL
5220 EXPECT_B2FATAL(Manager::Instance().getVariable("KSFWVariables(NONSENSE)"));
5221
5222 // check for NaN if we don't have a CS object for this particle
5223 StoreArray<Particle> myParticles;
5224 const Particle* particle_with_no_cs = myParticles.appendNew();
5225 const Manager::Var* var = Manager::Instance().getVariable("KSFWVariables(mm2)");
5226 EXPECT_TRUE(std::isnan(std::get<double>(var->function(particle_with_no_cs))));
5227
5228 // check that FS1 set as third argument, throws a B2ERROR
5229 EXPECT_B2ERROR(Manager::Instance().getVariable("KSFWVariables(et, mask, FS1)"));
5230 }
5231
5232 TEST_F(MetaVariableTest, CleoConeCS)
5233 {
5234 // simple tests that do not require the ROE builder nor the CS builder
5235
5236 // check that garbage input throws helpful B2FATAL
5237 EXPECT_B2FATAL(Manager::Instance().getVariable("CleoConeCS(NONSENSE)"));
5238
5239 // check for NaN if we don't have a CS object for this particle
5240 StoreArray<Particle> myParticles;
5241 const Particle* particle_with_no_cs = myParticles.appendNew();
5242 const Manager::Var* var = Manager::Instance().getVariable("CleoConeCS(0)");
5243 EXPECT_TRUE(std::isnan(std::get<double>(var->function(particle_with_no_cs))));
5244
5245 // check that string other than ROE as second argument, which is interpreted as mask name, returns NaN
5246 var = Manager::Instance().getVariable("CleoConeCS(0, NOTROE)");
5247 EXPECT_TRUE(std::isnan(std::get<double>(var->function(particle_with_no_cs))));
5248
5249 // check that ROE set as third argument, throws a B2ERROR
5250 EXPECT_B2ERROR(Manager::Instance().getVariable("CleoConeCS(0, mask, ROE)"));
5251 }
5252
5253 TEST_F(MetaVariableTest, TransformedNetworkOutput)
5254 {
5255 // check that garbage input throws helpful B2FATAL
5256 EXPECT_B2FATAL(Manager::Instance().getVariable("transformedNetworkOutput(NONSENSE)"));
5257
5258 // check that helpful B2FATAL is thrown if second or third argument is not a double
5259 EXPECT_B2FATAL(Manager::Instance().getVariable("transformedNetworkOutput(NONEXISTENT, 0, NOTDOUBLE)"));
5260 EXPECT_B2FATAL(Manager::Instance().getVariable("transformedNetworkOutput(NONEXISTENT, NOTDOUBLE, 1)"));
5261
5262 // check for NaN if network output variable does not exist (no matter whether particle is provided or not)
5263 StoreArray<Particle> myParticles;
5264 const Particle* particle = myParticles.appendNew();
5265 const Manager::Var* var = Manager::Instance().getVariable("transformedNetworkOutput(NONEXISTENT, 0, 1)");
5266 EXPECT_TRUE(std::isnan(std::get<double>(var->function(particle))));
5267 StoreObjPtr<EventExtraInfo> eventExtraInfo;
5268 if (not eventExtraInfo.isValid())
5269 eventExtraInfo.create();
5270 var = Manager::Instance().getVariable("transformedNetworkOutput(NONEXISTENT, 0, 1)");
5271 EXPECT_TRUE(std::isnan(std::get<double>(var->function(nullptr))));
5272 }
5273}
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