Belle II Software development
FilterCalculator.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8#include <hlt/softwaretrigger/calculations/FilterCalculator.h>
9#include <hlt/softwaretrigger/calculations/utilities.h>
10
11#include <Math/Vector3D.h>
12#include <Math/Vector4D.h>
13#include <Math/VectorUtil.h>
14
15#include <mdst/dataobjects/TrackFitResult.h>
16#include <mdst/dataobjects/HitPatternCDC.h>
17
18#include <analysis/dataobjects/Particle.h>
19#include <analysis/VertexFitting/KFit/VertexFitKFit.h>
20
21#include <framework/logging/Logger.h>
22
23#include <cmath>
24#include <numeric>
25#include <stdexcept>
26#include <optional>
27
28using namespace Belle2;
29using namespace SoftwareTrigger;
30
34 double pT = NAN;
36 const Track* track = nullptr;
42 double pCMS = NAN;
44 double pLab = NAN;
46 ROOT::Math::PxPyPzEVector p4CMS;
48 ROOT::Math::PxPyPzEVector p4Lab;
49};
50
54 const ECLCluster* cluster = nullptr;
56 double energyCMS = NAN;
58 double energyLab = NAN;
60 ROOT::Math::PxPyPzEVector p4CMS;
62 ROOT::Math::PxPyPzEVector p4Lab;
64 bool isTrack = false;
66 double clusterTime = NAN;
67};
68
70const double flatBoundaries[10] = {0., 19., 22., 25., 30., 35., 45., 60., 90., 180.};
71
72
73FilterCalculator::FilterCalculator() : m_bitsNN("CDCTriggerNNBits")
74{
75
76}
77
79{
80 m_tracks.isRequired();
81 m_eclClusters.isRequired();
82 m_l1Trigger.isOptional();
83 m_bitsNN.isOptional();
84}
85
86void FilterCalculator::doCalculation(SoftwareTriggerObject& calculationResult)
87{
88 calculationResult["nTrkLoose"] = 0;
89 calculationResult["nTrkTight"] = 0;
90 calculationResult["ee2leg"] = 0;
91 calculationResult["nEmedium"] = 0;
92 calculationResult["nElow"] = 0;
93 calculationResult["nEhigh"] = 0;
94 calculationResult["nE180Lab"] = 0;
95 calculationResult["nE300Lab"] = 0;
96 calculationResult["nE500Lab"] = 0;
97 calculationResult["nE2000CMS"] = 0;
98 calculationResult["nE4000CMS"] = 0;
99 calculationResult["nE250Lab"] = 0;
100 calculationResult["nMaxEPhotonAcc"] = 0;
101 calculationResult["dphiCmsClust"] = NAN;
103 calculationResult["netChargeLoose"] = 0;
104 calculationResult["maximumPCMS"] = NAN;
105 calculationResult["maximumPLab"] = NAN;
106 calculationResult["eexx"] = 0;
107 calculationResult["ee1leg1trk"] = 0;
108 calculationResult["nEhighLowAng"] = 0;
109 calculationResult["nEsingleClust"] = 0;
110 calculationResult["nEsinglePhotonBarrel"] = 0;
111 calculationResult["nEsinglePhotonExtendedBarrel"] = 0;
112 calculationResult["nEsinglePhotonEndcap"] = 0;
113 calculationResult["nEsingleElectronBarrel"] = 0;
114 calculationResult["nEsingleElectronExtendedBarrel"] = 0;
115 calculationResult["nReducedEsinglePhotonReducedBarrel"] = 0;
116 calculationResult["nVetoClust"] = 0;
117 calculationResult["chrgClust2GeV"] = 0;
118 calculationResult["neutClust045GeVAcc"] = 0;
119 calculationResult["neutClust045GeVBarrel"] = 0;
120 calculationResult["singleTagLowMass"] = 0;
121 calculationResult["singleTagHighMass"] = 0;
122 calculationResult["n2GeVNeutBarrel"] = 0;
123 calculationResult["n2GeVNeutEndcap"] = 0;
124 calculationResult["n2GeVChrg"] = 0;
125 calculationResult["n2GeVPhotonBarrel"] = 0;
126 calculationResult["n2GeVPhotonEndcap"] = 0;
127 calculationResult["ee1leg"] = 0;
128 calculationResult["ee1leg1clst"] = 0;
129 calculationResult["ee1leg1e"] = 0;
130 calculationResult["ee2clst"] = 0;
131 calculationResult["gg2clst"] = 0;
132 calculationResult["eeee"] = 0;
133 calculationResult["eemm"] = 0;
134 calculationResult["eexxSelect"] = 0;
135 calculationResult["radBhabha"] = 0;
136 calculationResult["eeBrem"] = 0;
137 calculationResult["isrRadBhabha"] = 0;
138 calculationResult["muonPairECL"] = 0;
139 calculationResult["ggHighPt"] = 0;
140 calculationResult["selectee1leg1trk"] = 0;
141 calculationResult["selectee1leg1clst"] = 0;
142 calculationResult["selectee"] = 0;
143 calculationResult["ggBarrelVL"] = 0;
144 calculationResult["ggBarrelLoose"] = 0;
145 calculationResult["ggBarrelTight"] = 0;
146 calculationResult["ggEndcapVL"] = 0;
147 calculationResult["ggEndcapLoose"] = 0;
148 calculationResult["ggEndcapTight"] = 0;
149 calculationResult["muonPairV"] = 0;
150 calculationResult["selectmumu"] = 0;
151 calculationResult["singleMuon"] = 0;
152 calculationResult["cosmic"] = 0;
153 calculationResult["displacedVertex"] = 0;
154 calculationResult["eeFlat0"] = 0;
155 calculationResult["eeFlat1"] = 0;
156 calculationResult["eeFlat2"] = 0;
157 calculationResult["eeFlat3"] = 0;
158 calculationResult["eeFlat4"] = 0;
159 calculationResult["eeFlat5"] = 0;
160 calculationResult["eeFlat6"] = 0;
161 calculationResult["eeFlat7"] = 0;
162 calculationResult["eeFlat8"] = 0;
163 calculationResult["eeOneClust"] = 0;
164
165 //..New track definitions
166 calculationResult["nTrkLooseB"] = 0;
167 calculationResult["nTrkTightB"] = 0;
168 calculationResult["maximumPCMSB"] = NAN;
169 calculationResult["netChargeLooseB"] = 0;
170 calculationResult["muonPairVB"] = 0;
171 calculationResult["eeBremB"] = 0;
172 calculationResult["singleTagLowMassB"] = 0;
173 calculationResult["singleTagHighMassB"] = 0;
174 calculationResult["radBhabhaB"] = 0;
177 // Passed on L1 information
178 if (m_l1Trigger.isValid()) {
179 calculationResult["l1_trigger_random"] = m_l1Trigger->getTimType() == TRGSummary::ETimingType::TTYP_RAND;
180 calculationResult["l1_trigger_delayed_bhabha"] = m_l1Trigger->getTimType() == TRGSummary::ETimingType::TTYP_DPHY;
181 calculationResult["l1_trigger_poisson"] = m_l1Trigger->getTimType() == TRGSummary::ETimingType::TTYP_POIS;
182 bool bha3d;
183 try {
184 bha3d = m_l1Trigger->testPsnm("bha3d");
185 } catch (const std::exception&) {
186 bha3d = false;
187 }
188 bool bhapurPsnm;
189 try {
190 bhapurPsnm = m_l1Trigger->testPsnm("bhapur");
191 } catch (const std::exception&) {
192 bhapurPsnm = false;
193 }
194 bool bhapurFtdl;
195 try {
196 bhapurFtdl = m_l1Trigger->testFtdl("bhapur");
197 } catch (const std::exception&) {
198 bhapurFtdl = false;
199 }
200 bool lml1;
201 try {
202 lml1 = m_l1Trigger->testPsnm("lml1");
203 } catch (const std::exception&) {
204 lml1 = false;
205 }
206 bool l1_bit_f;
207 try {
208 l1_bit_f = m_l1Trigger->testPsnm("fpre");
209 } catch (const std::exception&) {
210 l1_bit_f = false;
211 }
212 calculationResult["bha3d"] = bha3d;
213 calculationResult["bhapur"] = bhapurPsnm;
214 calculationResult["bhapur_lml1"] = lml1 and bhapurFtdl;
215 calculationResult["l1_bit_f"] = l1_bit_f;
216 } else {
217 calculationResult["l1_trigger_random"] = 1; // save every event if no L1 trigger info
218 calculationResult["l1_trigger_delayed_bhabha"] = 0;
219 calculationResult["l1_trigger_poisson"] = 0;
220 calculationResult["bha3d"] = 0;
221 calculationResult["bhapur"] = 0;
222 calculationResult["bhapur_lml1"] = 0;
223 calculationResult["l1_bit_f"] = 0;
224 }
225
226 // Every 256th event has CDC NN trigger information
227 calculationResult["l1_trg_NN_info"] = 0;
228 if (m_bitsNN.isValid() and m_bitsNN.getEntries() > 0) {calculationResult["l1_trg_NN_info"] = 1;}
229
230 calculationResult["true"] = 1;
231 calculationResult["false"] = 0;
232
233 // Some utilities
234 // TODO: into constructor
235 ClusterUtils cUtil;
236 const ROOT::Math::XYZVector clustervertex = cUtil.GetIPPosition();
237 PCmsLabTransform boostrotate;
238 ROOT::Math::PxPyPzEVector p4ofCOM;
239 p4ofCOM.SetPxPyPzE(0, 0, 0, boostrotate.getCMSEnergy());
240
241 // Pointers to the two tracks with the maximum pt
242 std::map<short, std::optional<MaximumPtTrack>> maximumPtTracks = {
243 { -1, {}}, {1, {}}
244 };
245
246 // Pointer to the two tracks with maximum pt without a cut applied on z0 (used for cosmic trigger)
247 std::map<short, std::optional<MaximumPtTrack>> maximumPtTracksWithoutZCut = {
248 { -1, {}}, {1, {}}
249 };
250
251 // --- Track variables -- //
252 for (const Track& track : m_tracks) {
253 const TrackFitResult* trackFitResult = track.getTrackFitResultWithClosestMass(Const::pion);
254 if (not trackFitResult) {
255 // Hu? No track fit result for pion? Ok, lets skip this track
256 continue;
257 }
258
259 // TODO: Temporary cut on number of CDC hits
260 if (trackFitResult->getHitPatternCDC().getNHits() == 0) {
261 continue;
262 }
263
264 // Count loose and tight tracks
265 const double z0 = trackFitResult->getZ0();
266 if (std::abs(z0) < m_tightTrkZ0) {
267 calculationResult["nTrkTight"] += 1;
268 }
269
270 // From here on use only tracks with defined charge
271 const short charge = trackFitResult->getChargeSign();
272 if (charge == 0) {
273 continue;
274 }
275
276 const ROOT::Math::PxPyPzEVector& momentumLab = trackFitResult->get4Momentum();
277 const ROOT::Math::PxPyPzEVector momentumCMS = boostrotate.rotateLabToCms() * momentumLab;
278 double pCMS = momentumCMS.P();
279 double pLab = momentumLab.P();
280
281 // Find the maximum pt negative [0] and positive [1] tracks without z0 cut
282 const double pT = trackFitResult->getTransverseMomentum();
283 const auto& currentMaximum = maximumPtTracksWithoutZCut.at(charge);
284 if (not currentMaximum or pT > currentMaximum->pT) {
285 MaximumPtTrack newMaximum;
286 newMaximum.pT = pT;
287 newMaximum.track = &track;
288 newMaximum.pCMS = pCMS;
289 newMaximum.pLab = pLab;
290 newMaximum.p4CMS = momentumCMS;
291 newMaximum.p4Lab = momentumLab;
292 maximumPtTracksWithoutZCut[charge] = newMaximum;
293 }
294
295 // Loose tracks
296 if (std::abs(z0) < m_looseTrkZ0) {
297 calculationResult["nTrkLoose"] += 1;
298 calculationResult["netChargeLoose"] += charge;
299
300 if (std::isnan(calculationResult["maximumPCMS"]) or pCMS > calculationResult["maximumPCMS"]) {
301 calculationResult["maximumPCMS"] = pCMS;
302 }
303
304 if (std::isnan(calculationResult["maximumPLab"]) or pLab > calculationResult["maximumPLab"]) {
305 calculationResult["maximumPLab"] = pLab;
306 }
307
308 // Find the maximum pt negative [0] and positive [1] tracks
309 const double pTLoose = trackFitResult->getTransverseMomentum();
310 const auto& currentMaximumLoose = maximumPtTracks.at(charge);
311 if (not currentMaximumLoose or pTLoose > currentMaximumLoose->pT) {
312 MaximumPtTrack newMaximum;
313 newMaximum.pT = pTLoose;
314 newMaximum.track = &track;
315 newMaximum.pCMS = pCMS;
316 newMaximum.pLab = momentumLab.P();
317 newMaximum.p4CMS = momentumCMS;
318 newMaximum.p4Lab = momentumLab;
319 maximumPtTracks[charge] = newMaximum;
320 }
321 }
322
323 //..New tighter track definitions.
324 // We can use pCMS and charge from above, because every looseB track is also a loose track
325 if (trackFitResult->getHitPatternCDC().getNHits() >= 5) {
326 if (std::abs(z0) < 1.) {calculationResult["nTrkTightB"] += 1;}
327 if (std::abs(z0) < 5.) {
328 calculationResult["nTrkLooseB"] += 1;
329 calculationResult["netChargeLooseB"] += charge;
330 if (std::isnan(calculationResult["maximumPCMSB"]) or pCMS > calculationResult["maximumPCMSB"]) {
331 calculationResult["maximumPCMSB"] = pCMS;
332
333 }
334 }
335 }
336
337 } // End loop over tracks
338
339
340 // -- Cluster variables -- //
341 std::vector<SelectedECLCluster> selectedClusters;
342 for (const ECLCluster& cluster : m_eclClusters) {
343 // Use the photon hypothesis, and only look at clusters with times < 200 ns
344 const double time = cluster.getTime();
345 if (not cluster.hasHypothesis(Belle2::ECLCluster::EHypothesisBit::c_nPhotons) or
346 std::abs(time) > 200 or
347 cluster.getEnergy(Belle2::ECLCluster::EHypothesisBit::c_nPhotons) < 0.1) {
348 continue;
349 }
350
351 const double dt99 = cluster.getDeltaTime99();
352
353 // Store cluster information
354 SelectedECLCluster selectedCluster;
355 selectedCluster.p4Lab = cUtil.Get4MomentumFromCluster(&cluster, clustervertex,
357 selectedCluster.p4CMS = boostrotate.rotateLabToCms() * selectedCluster.p4Lab; // was clustp4COM
358 selectedCluster.cluster = &cluster;
359 selectedCluster.clusterTime = time / dt99; // was clustT
360 selectedCluster.energyLab = selectedCluster.p4Lab.E();
361 selectedCluster.energyCMS = selectedCluster.p4CMS.E(); // was first of ECOMPair
362 selectedCluster.isTrack = cluster.isTrack(); // was tempCharge
363
364 selectedClusters.push_back(selectedCluster);
365
366 if (selectedCluster.energyCMS > m_E2min) {
367 calculationResult["nElow"] += 1;
368 }
369 if (selectedCluster.energyCMS > m_E0min) {
370 calculationResult["nEmedium"] += 1;
371 }
372 if (selectedCluster.energyCMS > m_Ehigh) {
373 calculationResult["nEhigh"] += 1;
374 }
375
376 if (selectedCluster.energyCMS > m_E0min and std::abs(selectedCluster.clusterTime) < 10) {
377 calculationResult["nVetoClust"] += 1;
378 }
379
380
381 //..Single cluster trigger objects use charge, Zernike moment, and thetaLab
382 const double thetaLab = selectedCluster.p4Lab.Theta() * TMath::RadToDeg();
383 const double zmva = cluster.getZernikeMVA();
384 const bool photon = zmva > 0.5 and not selectedCluster.isTrack;
385 const bool electron = zmva > 0.5 and selectedCluster.isTrack;
386
387 //..For 1 track radiative Bhabha control sample
388 if (selectedCluster.energyCMS > 2. and selectedCluster.isTrack) {
389 calculationResult["chrgClust2GeV"] += 1;
390 }
391 if (selectedCluster.energyCMS > 0.45 and not selectedCluster.isTrack) {
392 const bool isInAcceptance = 17. < thetaLab and thetaLab < 150.;
393 if (isInAcceptance) {calculationResult["neutClust045GeVAcc"] += 1;}
394 const bool isInBarrel = 30. < thetaLab and thetaLab < 130.;
395 if (isInBarrel) {calculationResult["neutClust045GeVBarrel"] += 1;}
396 }
397
398
399 // improved 3 cluster (4 cluster) trigger
400 const bool notInHighBackgroundEndcapRegion = 18.5 < thetaLab and thetaLab < 139.3;
401 if (selectedCluster.energyLab > m_EminLab and notInHighBackgroundEndcapRegion) {
402 calculationResult["nE180Lab"] += 1;
403 }
404
405 if (selectedCluster.energyLab > m_EminLab4Cluster and notInHighBackgroundEndcapRegion) {
406 calculationResult["nE300Lab"] += 1;
407 }
408
409 if (selectedCluster.energyLab > m_EminLab3Cluster and notInHighBackgroundEndcapRegion) {
410 calculationResult["nE500Lab"] += 1;
411 }
412
413 if (selectedCluster.energyCMS > m_Ehigh and notInHighBackgroundEndcapRegion) {
414 calculationResult["nE2000CMS"] += 1;
415 }
416
417 //..For two-photon fusion ALP trigger
418 if (selectedCluster.energyLab > 0.25) {
419 calculationResult["nE250Lab"] += 1;
420 }
421 if (selectedCluster.energyCMS > 4.) {
422 calculationResult["nE4000CMS"] += 1;
423 }
424
425 //..Single cluster triggers
426 if (selectedCluster.energyCMS > m_EsinglePhoton) {
427 calculationResult["nEsingleClust"] += 1;
428
429 const bool barrelRegion = thetaLab > 45 and thetaLab < 115;
430 const bool extendedBarrelRegion = thetaLab > 30 and thetaLab < 130;
431 const bool endcapRegion = (thetaLab > 22 and thetaLab < 45) or (thetaLab > 115 and thetaLab < 145);
432
433 if (photon and barrelRegion) {
434 calculationResult["nEsinglePhotonBarrel"] += 1;
435 }
436
437 if (photon and extendedBarrelRegion) {
438 calculationResult["nEsinglePhotonExtendedBarrel"] += 1;
439 }
440
441 if (electron and barrelRegion) {
442 calculationResult["nEsingleElectronBarrel"] += 1;
443 }
444
445 if (electron and extendedBarrelRegion) {
446 calculationResult["nEsingleElectronExtendedBarrel"] += 1;
447 }
448
449 if (photon and endcapRegion) {
450 calculationResult["nEsinglePhotonEndcap"] += 1;
451 }
452 }
453
454 if (selectedCluster.energyCMS > m_reducedEsinglePhoton) {
455 const bool reducedBarrelRegion = thetaLab > 44 and thetaLab < 98;
456
457 if (photon and reducedBarrelRegion) {
458 calculationResult["nReducedEsinglePhotonReducedBarrel"] += 1;
459 }
460 }
461
462 if (selectedCluster.energyCMS > m_Ehigh) {
463 // TODO: different definition!
464 const bool barrelRegion = thetaLab > 32 and thetaLab < 130;
465 const bool endcapRegion = (thetaLab > 22 and thetaLab < 32) or (thetaLab > 130 and thetaLab < 145);
466 const bool lowAngleRegion = thetaLab < 22 or thetaLab > 145;
467
468 if (not selectedCluster.isTrack and barrelRegion) {
469 calculationResult["n2GeVNeutBarrel"] += 1;
470 }
471 if (not selectedCluster.isTrack and endcapRegion) {
472 calculationResult["n2GeVNeutEndcap"] += 1;
473 }
474 if (selectedCluster.isTrack and not lowAngleRegion) {
475 calculationResult["n2GeVChrg"] += 1;
476 }
477 if (lowAngleRegion) {
478 calculationResult["nEhighLowAng"] += 1;
479 }
480 if (photon and barrelRegion) {
481 calculationResult["n2GeVPhotonBarrel"] += 1;
482 }
483 if (photon and endcapRegion) {
484 calculationResult["n2GeVPhotonEndcap"] += 1;
485 }
486 }
487 } // end of loop over clusters
488
489 //..Order clusters by CMS energy
490 std::sort(selectedClusters.begin(), selectedClusters.end(), [](const auto & lhs, const auto & rhs) {
491 return lhs.energyCMS > rhs.energyCMS;
492 });
493
494 // -- Bhabha and two-photon lepton preparation -- //
495 for (short charge : { -1, 1}) {
496 auto& maximumPtTrack = maximumPtTracks.at(charge);
497 if (not maximumPtTrack) {
498 continue;
499 }
500
501 // Prep max two tracks for Bhabha and two-photon lepton selections
502 // Track / cluster matching
503 for (auto& cluster : maximumPtTrack->track->getRelationsTo<ECLCluster>()) {
504 if (cluster.hasHypothesis(Belle2::ECLCluster::EHypothesisBit::c_nPhotons)) {
505 maximumPtTrack->clusterEnergySumLab += cluster.getEnergy(Belle2::ECLCluster::EHypothesisBit::c_nPhotons);
506 }
507 }
508 maximumPtTrack->clusterEnergySumCMS =
509 maximumPtTrack->clusterEnergySumLab * maximumPtTrack->pCMS / maximumPtTrack->pLab;
510
511 // Single leg Bhabha selections
512 if (maximumPtTrack->clusterEnergySumCMS > 4.5) {
513 calculationResult["ee1leg"] = 1;
514 }
515
516 // single muon
517 if (maximumPtTrack->pCMS > 3 and maximumPtTrack->clusterEnergySumLab > 0. and maximumPtTrack->clusterEnergySumLab < 1.) {
518 calculationResult["singleMuon"] = 1;
519 }
520 }
521
522 // Bhabha selections using two tracks
523 if (maximumPtTracks.at(-1) and maximumPtTracks.at(1)) {
524 const MaximumPtTrack& negativeTrack = *maximumPtTracks.at(-1);
525 const MaximumPtTrack& positiveTrack = *maximumPtTracks.at(1);
526
527 double dphi = std::abs(negativeTrack.p4CMS.Phi() - positiveTrack.p4CMS.Phi()) * TMath::RadToDeg();
528 if (dphi > 180) {
529 dphi = 360 - dphi;
530 }
531
532 const double negativeClusterSum = negativeTrack.clusterEnergySumCMS;
533 const double negativeClusterSumLab = negativeTrack.clusterEnergySumLab;
534 const double negativeP = negativeTrack.pCMS;
535 const double positiveClusterSum = positiveTrack.clusterEnergySumCMS;
536 const double positiveClusterSumLab = positiveTrack.clusterEnergySumLab;
537 const double positiveP = positiveTrack.pCMS;
538
539 // two leg Bhabha
540 const double thetaSum = (negativeTrack.p4CMS.Theta() + positiveTrack.p4CMS.Theta()) * TMath::RadToDeg();
541 const double dthetaSum = std::abs(thetaSum - 180);
542 const auto back2back = dphi > 175 and dthetaSum < 15;
543 if (back2back and negativeClusterSum > 3 and positiveClusterSum > 3 and
544 (negativeClusterSum > 4.5 or positiveClusterSum > 4.5)) {
545 calculationResult["ee2leg"] = 1;
546 }
547
548 // one leg one track Bhabha
549 if (back2back and ((negativeClusterSum > 4.5 and positiveP > 3) or (positiveClusterSum > 4.5 and negativeP > 3))) {
550 calculationResult["ee1leg1trk"] = 1;
551 }
552
553
554 // one leg plus one electron
555 if ((negativeClusterSum > 4.5 and positiveClusterSum > 0.8 * positiveP) or
556 (positiveClusterSum > 4.5 and negativeClusterSum > 0.8 * negativeP)) {
557 calculationResult["ee1leg1e"] = 1;
558 }
559
560 // eeee, eemm, mu mu, and radiative Bhabha selection
561 const ROOT::Math::PxPyPzEVector p4Miss = p4ofCOM - negativeTrack.p4CMS - positiveTrack.p4CMS;
562 const double pmissTheta = p4Miss.Theta() * TMath::RadToDeg();
563 const double pmissp = p4Miss.P();
564 const double relMissAngle0 = ROOT::Math::VectorUtil::Angle(negativeTrack.p4CMS, p4Miss) * TMath::RadToDeg();
565 const double relMissAngle1 = ROOT::Math::VectorUtil::Angle(positiveTrack.p4CMS, p4Miss) * TMath::RadToDeg();
566
567 const bool electronEP = positiveClusterSum > 0.8 * positiveP or negativeClusterSum > 0.8 * negativeP;
568 const bool notMuonPair = negativeClusterSumLab > 1 or positiveClusterSumLab > 1;
569 const double highp = std::max(negativeP, positiveP);
570 const double lowp = std::min(negativeP, positiveP);
571 const bool lowEdep = negativeClusterSumLab < 0.5 and positiveClusterSumLab < 0.5;
572
573 //..Select two photon fusion lepton pairs
574 if (calculationResult["maximumPCMS"] < 2 and dphi > 160 and (pmissTheta < 25. or pmissTheta > 155.)) {
575 calculationResult["eexxSelect"] = 1;
576 if (electronEP) {
577 calculationResult["eeee"] = 1;
578 } else {
579 calculationResult["eemm"] = 1;
580 }
581 }
582
583 //..Veto two photon fusion lepton pairs
584 if ((pmissTheta < 20. or pmissTheta > 160.) and
585 ((calculationResult["maximumPCMS"] < 1.2 and dphi > 150.) or
586 (calculationResult["maximumPCMS"] < 2. and 175. < dphi))) {
587 calculationResult["eexx"] = 1;
588 }
589
590 //..Radiative Bhabhas with missing momentum in acceptance
591 if (negativeP > 1. and pmissTheta > 10. and pmissTheta < 170. and positiveP > 1. and dphi < 170. and pmissp > 1. and electronEP) {
592 if (calculationResult["nTrkLoose"] == 2 and calculationResult["nTrkTight"] >= 1) {
593 calculationResult["radBhabha"] = 1;
594 }
595 if (calculationResult["nTrkLooseB"] == 2 and calculationResult["nTrkTightB"] >= 1) {
596 calculationResult["radBhabhaB"] = 1;
597 }
598 }
599
600 //..ISR radiative Bhabha with missing momentum down beam pipe
601 if (negativeP > 2. and positiveP > 2. and 2 == calculationResult["nTrkLoose"] and
602 calculationResult["nTrkTight"] >= 1 and dphi > 175. and
603 (pmissTheta < 5. or pmissTheta > 175.) and electronEP) {
604 calculationResult["isrRadBhabha"] = 1;
605 }
606
607 //..Veto Bhabha with hard brem
608 if (highp > 4.5 and notMuonPair and pmissp > 1. and (relMissAngle0 < 5. or relMissAngle1 < 5.)) {
609 if (calculationResult["nTrkLoose"] == 2) { calculationResult["eeBrem"] = 1;}
610 if (calculationResult["nTrkLooseB"] >= 1) { calculationResult["eeBremB"] = 1;}
611 }
612
613 //..Veto e+e- -> mu+mu-
614 if (highp > 4.5 and lowEdep and thetaSum > 175. and thetaSum < 185. and dphi > 175.) {
615 if (calculationResult["nTrkLoose"] == 2) {calculationResult["muonPairV"] = 1;}
616 if (calculationResult["nTrkLooseB"] == 2) {calculationResult["muonPairVB"] = 1;}
617 }
618
619 //..Select e+e- -> mu+mu-
620 if (highp > 3. and lowp > 2.5 and dphi > 165. and
621 ((negativeClusterSumLab > 0. and negativeClusterSumLab < 1.) or
622 (positiveClusterSumLab > 0. and positiveClusterSumLab < 1.))) {
623 calculationResult["selectmumu"] = 1;
624 }
625 }
626
627 //..Filters and vetoes using two maximum-energy clusters
628 if (selectedClusters.size() >= 2) {
629 const SelectedECLCluster& firstCluster = selectedClusters[0];
630 const SelectedECLCluster& secondCluster = selectedClusters[1];
631
632 double dphi = std::abs(firstCluster.p4CMS.Phi() - secondCluster.p4CMS.Phi()) * TMath::RadToDeg();
633 if (dphi > 180) {
634 dphi = 360 - dphi;
635 }
636 double thetaSum = (firstCluster.p4CMS.Theta() + secondCluster.p4CMS.Theta()) * TMath::RadToDeg();
637 double dthetaSum = std::abs(thetaSum - 180);
638
639 //..Quantities for two-photon fusion triggers
640 calculationResult["dphiCmsClust"] = dphi;
641 for (int ic = 0; ic < 2; ic++) {
642 const double thetaLab = selectedClusters[ic].p4Lab.Theta() * TMath::RadToDeg();
643 const bool isInAcceptance = 17. < thetaLab and thetaLab < 150.;
644 const ECLCluster* cluster = selectedClusters[ic].cluster;
645 const double zmva = cluster->getZernikeMVA();
646 const bool photon = zmva > 0.5 and not selectedClusters[ic].isTrack;
647 if (isInAcceptance and photon) {calculationResult["nMaxEPhotonAcc"] += 1;}
648 }
649
650 const double firstEnergy = firstCluster.p4CMS.E();
651 const double secondEnergy = secondCluster.p4CMS.E();
652
653 const bool highEnergetic = firstEnergy > 3 and secondEnergy > 3 and (firstEnergy > 4.5 or secondEnergy > 4.5);
654
655 if (dphi > 160 and dphi < 178 and dthetaSum < 15 and highEnergetic) {
656 calculationResult["ee2clst"] = 1;
657 }
658
659 if (dphi > 178 and dthetaSum < 15 and highEnergetic) {
660 calculationResult["gg2clst"] = 1;
661 }
662
663 if ((calculationResult["ee2clst"] == 1 or calculationResult["gg2clst"] == 1) and
664 calculationResult["ee1leg"] == 1) {
665 calculationResult["ee1leg1clst"] = 1;
666 }
667
668 const double Elab0 = firstCluster.p4Lab.E();
669 const double Elab1 = secondCluster.p4Lab.E();
670
671 // gg and mumu accept triggers using ECL
672 if (firstEnergy > 2 and secondEnergy > 2) {
673 const double thetaLab0 = firstCluster.p4Lab.Theta() * TMath::RadToDeg();
674 const double thetaLab1 = secondCluster.p4Lab.Theta() * TMath::RadToDeg();
675
676 const bool barrel0 = 32. < thetaLab0 and thetaLab0 < 130.;
677 const bool barrel1 = 32. < thetaLab1 and thetaLab1 < 130.;
678 const bool oneClustersAbove4 = firstEnergy > 4 or secondEnergy > 4;
679 const bool oneIsNeutral = not firstCluster.isTrack or not secondCluster.isTrack;
680 const bool bothAreNeutral = not firstCluster.isTrack and not secondCluster.isTrack;
681 const bool oneIsBarrel = barrel0 or barrel1;
682 const bool dphiCutExtraLoose = dphi > 175;
683 const bool dphiCutLoose = dphi > 177;
684 const bool dphiCutTight = dphi > 177.5;
685
686 if (dphiCutExtraLoose and oneIsNeutral and oneIsBarrel) {
687 calculationResult["ggBarrelVL"] = 1;
688 }
689 if (oneClustersAbove4 and dphiCutLoose and oneIsNeutral and oneIsBarrel) {
690 calculationResult["ggBarrelLoose"] = 1;
691 }
692 if (oneClustersAbove4 and dphiCutTight and bothAreNeutral and oneIsBarrel) {
693 calculationResult["ggBarrelTight"] = 1;
694 }
695 if (dphiCutExtraLoose and oneIsNeutral and not oneIsBarrel) {
696 calculationResult["ggEndcapVL"] = 1;
697 }
698 if (oneClustersAbove4 and dphiCutLoose and oneIsNeutral and not oneIsBarrel) {
699 calculationResult["ggEndcapLoose"] = 1;
700 }
701 if (oneClustersAbove4 and dphiCutTight and bothAreNeutral and not oneIsBarrel) {
702 calculationResult["ggEndcapTight"] = 1;
703 }
704 }
705
706 const double minEnergy = std::min(Elab0, Elab1);
707 const double maxEnergy = std::max(Elab0, Elab1);
708 if (dphi > 155 and thetaSum > 165 and thetaSum < 195 and minEnergy > 0.15 and minEnergy < 0.5 and
709 maxEnergy > 0.15 and maxEnergy < 0.5) {
710 calculationResult["muonPairECL"] = 1;
711 }
712
713 //..diPhoton line
714 const double thetaLab0 = firstCluster.p4Lab.Theta() * TMath::RadToDeg();
715 const double thetaLab1 = secondCluster.p4Lab.Theta() * TMath::RadToDeg();
716 const bool inHieRegion0 = thetaLab0 > 26. and thetaLab0 < 130.;
717 const bool inHieRegion1 = thetaLab1 > 26. and thetaLab1 < 130.;
718 const bool firstIsNeutral = not firstCluster.isTrack;
719 const bool secondIsNeutral = not secondCluster.isTrack;
720
721 if (secondEnergy > 0.3 and inHieRegion0 and inHieRegion1 and firstIsNeutral and secondIsNeutral) {
722 const ROOT::Math::PxPyPzEVector ggP4CMS = firstCluster.p4CMS + secondCluster.p4CMS;
723 if (ggP4CMS.pt() > 1.) {calculationResult["ggHighPt"] = 1;}
724 }
725
726 } // end of two-clusters lines
727
728 // Bhabha accept triggers.
729 // Use theta_lab of negative track if available; otherwise cluster.
730 double thetaFlatten = 0;
731
732 // One leg, one cluster.
733 for (short charge : { -1, 1}) {
734 const auto& maximumPtTrack = maximumPtTracks.at(charge);
735 if (not maximumPtTrack) {
736 continue;
737 }
738
739 if (maximumPtTrack->clusterEnergySumCMS > 1.5) {
740 double invMass = 0.;
741 double tempFlatten = 0.;
742 for (const SelectedECLCluster& cluster : selectedClusters) {
743 double tempInvMass = (maximumPtTrack->p4Lab + cluster.p4Lab).M();
744 if (tempInvMass > invMass) {
745 invMass = tempInvMass;
746 if (charge == 1) {
747 tempFlatten = cluster.p4Lab.Theta() * TMath::RadToDeg();
748 }
749 }
750 }
751 if (charge == -1) {
752 tempFlatten = maximumPtTrack->p4Lab.Theta() * TMath::RadToDeg();
753 }
754 if (invMass > 5.29) {
755 calculationResult["selectee1leg1clst"] = 1;
756 thetaFlatten = tempFlatten;
757 }
758 }
759 }
760
761 // Two legs
762 if (maximumPtTracks.at(-1) and maximumPtTracks.at(1)) {
763 const MaximumPtTrack& negativeTrack = *maximumPtTracks.at(-1);
764 const MaximumPtTrack& positiveTrack = *maximumPtTracks.at(1);
765 const double invMass = (negativeTrack.p4Lab + positiveTrack.p4Lab).M();
766 if (invMass > 5.29 and (negativeTrack.clusterEnergySumCMS > 1.5 or positiveTrack.clusterEnergySumCMS > 1.5)) {
767 calculationResult["selectee1leg1trk"] = 1;
768 }
769
770 thetaFlatten = negativeTrack.p4Lab.Theta() * TMath::RadToDeg();
771
772 // Two tracks but (exactly) 1 high energy cluster
773 const bool missNegClust = positiveTrack.clusterEnergySumCMS > 4.5 and negativeTrack.clusterEnergySumCMS < 1.;
774 const bool missPosClust = negativeTrack.clusterEnergySumCMS > 4.5 and positiveTrack.clusterEnergySumCMS < 1.;
775 if ((invMass > 9.) and (missNegClust or missPosClust)) {
776 calculationResult["eeOneClust"] = 1;
777 }
778 }
779
780 if (calculationResult["selectee1leg1trk"] == 1 or calculationResult["selectee1leg1clst"] == 1) {
781 for (int iflat = 0; iflat < 9; iflat++) {
782 const std::string& eeFlatName = "eeFlat" + std::to_string(iflat);
783 calculationResult[eeFlatName] =
784 thetaFlatten > flatBoundaries[iflat] and thetaFlatten < flatBoundaries[iflat + 1];
785 if (calculationResult[eeFlatName]) {
786 calculationResult["selectee"] = 1;
787 }
788 }
789 }
790
791 // Single tag pi0 / eta dedicated lines
792 if (calculationResult["nTrkLoose"] == 1 and calculationResult["maximumPCMS"] > 0.8 and selectedClusters.size() >= 2) {
793
794 decltype(selectedClusters) selectedSingleTagClusters(selectedClusters.size());
795 auto lastItem = std::copy_if(selectedClusters.begin(), selectedClusters.end(), selectedSingleTagClusters.begin(),
796 [](auto & cluster) {
797 const bool isNeutralCluster = not cluster.isTrack;
798 const bool hasEnoughEnergy = cluster.energyLab > 0.1;
799 const double clusterThetaLab = cluster.p4Lab.Theta() * TMath::RadToDeg();
800 const bool isInAcceptance = 17 < clusterThetaLab and clusterThetaLab < 150.;
801 return isNeutralCluster and hasEnoughEnergy and isInAcceptance;
802 });
803 selectedSingleTagClusters.resize(std::distance(selectedSingleTagClusters.begin(), lastItem));
804
805 if (selectedSingleTagClusters.size() >= 2) { // One track and at least two clusters are found
806
807 const auto& track = maximumPtTracks.at(-1) ? *maximumPtTracks.at(-1) : *maximumPtTracks.at(1);
808 // in real signal, the pi0 decay daughters are always the two most-energetic neutral clusters.
809 const auto& firstCluster = selectedSingleTagClusters[0];
810 const auto& secondCluster = selectedSingleTagClusters[1];
811
812 const ROOT::Math::PxPyPzEVector trackP4CMS = track.p4CMS;
813 const ROOT::Math::PxPyPzEVector pi0P4CMS = firstCluster.p4CMS + secondCluster.p4CMS;
814
815 const bool passPi0ECMS = pi0P4CMS.E() > 1. and pi0P4CMS.E() < 0.525 * p4ofCOM.M();
816 const double thetaSumCMS = (pi0P4CMS.Theta() + trackP4CMS.Theta()) * TMath::RadToDeg();
817 const bool passThetaSum = thetaSumCMS < 170. or thetaSumCMS > 190.;
818
819 double dphiCMS = std::abs(trackP4CMS.Phi() - pi0P4CMS.Phi()) * TMath::RadToDeg();
820 if (dphiCMS > 180) {
821 dphiCMS = 360 - dphiCMS;
822 }
823 const bool passdPhi = dphiCMS > 160.;
824
825 if (passPi0ECMS and passThetaSum and passdPhi and pi0P4CMS.M() < 0.7) {
826 calculationResult["singleTagLowMass"] = 1;
827 } else if (passPi0ECMS and passThetaSum and passdPhi and pi0P4CMS.M() > 0.7) {
828 calculationResult["singleTagHighMass"] = 1;
829 }
830 }
831 }
832
833 //..Updated to use new track definitions
834 if (calculationResult["nTrkLooseB"] == 1 and calculationResult["maximumPCMSB"] > 0.8 and selectedClusters.size() >= 2) {
835
836 decltype(selectedClusters) selectedSingleTagClusters(selectedClusters.size());
837 auto lastItem = std::copy_if(selectedClusters.begin(), selectedClusters.end(), selectedSingleTagClusters.begin(),
838 [](auto & cluster) {
839 const bool isNeutralCluster = not cluster.isTrack;
840 const bool hasEnoughEnergy = cluster.energyLab > 0.1;
841 const double clusterThetaLab = cluster.p4Lab.Theta() * TMath::RadToDeg();
842 const bool isInAcceptance = 17 < clusterThetaLab and clusterThetaLab < 150.;
843 return isNeutralCluster and hasEnoughEnergy and isInAcceptance;
844 });
845 selectedSingleTagClusters.resize(std::distance(selectedSingleTagClusters.begin(), lastItem));
846
847 if (selectedSingleTagClusters.size() >= 2) { // One track and at least two clusters are found
848
849 const auto& track = maximumPtTracks.at(-1) ? *maximumPtTracks.at(-1) : *maximumPtTracks.at(1);
850 // in real signal, the pi0 decay daughters are always the two most-energetic neutral clusters.
851 const auto& firstCluster = selectedSingleTagClusters[0];
852 const auto& secondCluster = selectedSingleTagClusters[1];
853
854 const ROOT::Math::PxPyPzEVector trackP4CMS = track.p4CMS;
855 const ROOT::Math::PxPyPzEVector pi0P4CMS = firstCluster.p4CMS + secondCluster.p4CMS;
856
857 const bool passPi0ECMS = pi0P4CMS.E() > 1. and pi0P4CMS.E() < 0.525 * p4ofCOM.M();
858 const double thetaSumCMS = (pi0P4CMS.Theta() + trackP4CMS.Theta()) * TMath::RadToDeg();
859 const bool passThetaSum = thetaSumCMS < 170. or thetaSumCMS > 190.;
860
861 double dphiCMS = std::abs(trackP4CMS.Phi() - pi0P4CMS.Phi()) * TMath::RadToDeg();
862 if (dphiCMS > 180) {
863 dphiCMS = 360 - dphiCMS;
864 }
865 const bool passdPhi = dphiCMS > 160.;
866
867 if (passPi0ECMS and passThetaSum and passdPhi and pi0P4CMS.M() < 0.7) {
868 calculationResult["singleTagLowMassB"] = 1;
869 } else if (passPi0ECMS and passThetaSum and passdPhi and pi0P4CMS.M() > 0.7) {
870 calculationResult["singleTagHighMassB"] = 1;
871 }
872 }
873 }
874
875 //..Cosmic selection. Need exactly two tracks.
876 if (m_tracks.getEntries() == 2) {
877
878 const auto negTrack = maximumPtTracksWithoutZCut.at(-1);
879 const auto posTrack = maximumPtTracksWithoutZCut.at(1);
880
881 if (negTrack and posTrack) {
882
883 const double maxNegpT = negTrack->pT;
884 const double maxPospT = posTrack->pT;
885
886 auto accumulatePhotonEnergy = [](double result, const auto & cluster) {
887 return result + (cluster.hasHypothesis(Belle2::ECLCluster::EHypothesisBit::c_nPhotons) ? cluster.getEnergy(
889 };
890
891 const auto& clustersOfNegTrack = negTrack->track->getRelationsTo<ECLCluster>();
892 const auto& clustersOfPosTrack = posTrack->track->getRelationsTo<ECLCluster>();
893
894 const double maxClusterENeg = std::accumulate(clustersOfNegTrack.begin(), clustersOfNegTrack.end(), 0.0, accumulatePhotonEnergy);
895 const double maxClusterEPos = std::accumulate(clustersOfPosTrack.begin(), clustersOfPosTrack.end(), 0.0, accumulatePhotonEnergy);
896
897 const ROOT::Math::PxPyPzEVector& momentumLabNeg(negTrack->p4Lab);
898 const ROOT::Math::PxPyPzEVector& momentumLabPos(posTrack->p4Lab);
899
900 const double& z0Neg = negTrack->track->getTrackFitResultWithClosestMass(Const::pion)->getZ0();
901 const double& d0Neg = negTrack->track->getTrackFitResultWithClosestMass(Const::pion)->getD0();
902 const double& z0Pos = posTrack->track->getTrackFitResultWithClosestMass(Const::pion)->getZ0();
903 const double& d0Pos = posTrack->track->getTrackFitResultWithClosestMass(Const::pion)->getD0();
904
905 // Select cosmic using these tracks
906 const bool goodMagneticRegion = (z0Neg<m_goodMagneticRegionZ0 or std::abs(d0Neg)>m_goodMagneticRegionD0)
907 and (z0Pos<m_goodMagneticRegionZ0 or std::abs(d0Pos)>m_goodMagneticRegionD0);
908 if (maxNegpT > m_cosmicMinPt and maxPospT > m_cosmicMinPt and maxClusterENeg < m_cosmicMaxClusterEnergy
909 and maxClusterEPos < m_cosmicMaxClusterEnergy and goodMagneticRegion) {
910 double dphiLab = std::abs(momentumLabNeg.Phi() - momentumLabPos.Phi()) * TMath::RadToDeg();
911 if (dphiLab > 180) {
912 dphiLab = 360 - dphiLab;
913 }
914
915 const double thetaSumLab = (momentumLabNeg.Theta() + momentumLabPos.Theta()) * TMath::RadToDeg();
916
917 constexpr double phiBackToBackTolerance = 2.;
918 constexpr double thetaBackToBackTolerance = 2.;
919 if ((180 - dphiLab) < phiBackToBackTolerance and std::abs(180 - thetaSumLab) < thetaBackToBackTolerance) {
920 calculationResult["cosmic"] = 1;
921 }
922 }
923 }
924 }
925
926 //..Displaced vertex
927 // See https://indico.belle2.org/event/8973/ and references therein
928 if (maximumPtTracksWithoutZCut.at(-1) and maximumPtTracksWithoutZCut.at(1)) {
929
930 //..Make particles of the two highest pt tracks (without IP cut)
931 const auto nTrack = maximumPtTracksWithoutZCut.at(-1)->track;
932 Particle* nParticle = new Particle(nTrack, Const::pion);
933
934 const auto pTrack = maximumPtTracksWithoutZCut.at(1)->track;
935 Particle* pParticle = new Particle(pTrack, Const::pion);
936
937 //..Make a vertex of these two
939 vertexFit->addParticle(nParticle);
940 vertexFit->addParticle(pParticle);
941 vertexFit->doFit();
942
943 //..Vertex properties
944 const double chisq = vertexFit->getCHIsq();
945 const int ndf = vertexFit->getNDF();
946 const double vertexProb = TMath::Prob(chisq, ndf);
947 const auto vertexLocation = vertexFit->getVertex();
948 const double vertexXY = vertexLocation.perp();
949 const double vertexTheta = vertexLocation.theta() * TMath::RadToDeg();
950
951 //..Angular differaence of two tracks to reject cosmics
952 // Tolerance could be reduced from 10 deg to 2 deg if needed for physics reasons,
953 // for a 5% increase in the rate of selected displaced vertex triggers.
954 // See https://gitlab.desy.de/belle2/software/basf2/-/merge_requests/1867
955 const ROOT::Math::PxPyPzEVector& momentumLabNeg(maximumPtTracksWithoutZCut.at(-1)->p4Lab);
956 const ROOT::Math::PxPyPzEVector& momentumLabPos(maximumPtTracksWithoutZCut.at(1)->p4Lab);
957 const double thetaSumLab = (momentumLabNeg.Theta() + momentumLabPos.Theta()) * TMath::RadToDeg();
958 double dPhiLab = std::abs(momentumLabNeg.Phi() - momentumLabPos.Phi()) * TMath::RadToDeg();
959 if (dPhiLab > 180) {
960 dPhiLab = 360 - dPhiLab;
961 }
962 const double backToBackTolerance = 10.; // degrees
963 const bool backToBackLab = std::abs(thetaSumLab - 180.) < backToBackTolerance and std::abs(dPhiLab - 180.) < backToBackTolerance;
964
965 //..Select a displaced vertex
966 const double minProbChiVertex = 0.005; // minimum probability chi square. Many backgrounds have bad chi sq.
967 const double minXYVertex = 3.; // minimum xy of vertex (cm). Should pass track filters below this.
968 const double maxXYVertex = 60.; // maximum xy. Insufficient CDC for good reconstruction beyond this.
969 const double minThetaVertex = 30.; // Large Bhabha background at low angles.
970 const double maxThetaVertex = 120.; // Large Bhabha background at low angles.
971 if (vertexProb > minProbChiVertex and vertexXY > minXYVertex and vertexXY < maxXYVertex and vertexTheta > minThetaVertex
972 and vertexTheta < maxThetaVertex
973 and not backToBackLab) {calculationResult["displacedVertex"] = 1;}
974
975 //..Clean up
976 delete nParticle;
977 delete pParticle;
978 delete vertexFit;
979
980 }
981
982}
Class to provide momentum-related information from ECLClusters.
Definition: ClusterUtils.h:38
const ROOT::Math::PxPyPzEVector Get4MomentumFromCluster(const ECLCluster *cluster, ECLCluster::EHypothesisBit hypo)
Returns four momentum vector.
Definition: ClusterUtils.cc:25
const ROOT::Math::XYZVector GetIPPosition()
Returns default IP position from beam parameters.
static const ChargedStable pion
charged pion particle
Definition: Const.h:661
ECL cluster data.
Definition: ECLCluster.h:27
@ c_nPhotons
CR is split into n photons (N1)
unsigned short getNHits() const
Get the total Number of CDC hits in the fit.
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.
Class to store reconstructed particles.
Definition: Particle.h:76
RelationVector< TO > getRelationsTo(const std::string &name="", const std::string &namedRelation="") const
Get the relations that point from this object to another store array.
double m_EminLab
which lab energy defines nE180Lab
double m_reducedEsinglePhoton
which CMS energy defines nReducedEsingle clusters
StoreObjPtr< TRGSummary > m_l1Trigger
Store Object with the trigger result.
double m_E0min
which CMS energy defines nEmedium
void requireStoreArrays() override
Require the particle list. We do not need more here.
void doCalculation(SoftwareTriggerObject &calculationResult) override
Actually write out the variables into the map.
double m_goodMagneticRegionZ0
maximum z0 for well understood magnetic field (cm)
double m_cosmicMinPt
which LAB pt defines a cosmic
double m_EsinglePhoton
which CMS energy defines nEsingleClust
double m_E2min
which CMS energy defines nElow
double m_tightTrkZ0
which Z0 defines a tight track
StoreArray< Track > m_tracks
Store Array of the tracks to be used.
double m_EminLab3Cluster
which lab energy defines nE500Lab
double m_Ehigh
which CMS energy defines nEhigh
StoreArray< ECLCluster > m_eclClusters
Store Array of the ecl clusters to be used.
double m_EminLab4Cluster
which lab energy defines nE300Lab
StoreArray< CDCTriggerUnpacker::NNBitStream > m_bitsNN
Store Object with the trigger NN bits.
FilterCalculator()
Set the default names for the store object particle lists.
double m_cosmicMaxClusterEnergy
which LAB cluster energy vetoes a cosmic candidate
double m_goodMagneticRegionD0
minimum d0 for well understood magnetic field, if z0 is large (cm)
double m_looseTrkZ0
which Z0 defines a loose track
@ TTYP_DPHY
delayed physics events for background
Definition: TRGSummary.h:65
@ TTYP_POIS
poisson random trigger
Definition: TRGSummary.h:73
@ TTYP_RAND
random trigger events
Definition: TRGSummary.h:67
Values of the result of a track fit with a given particle hypothesis.
short getChargeSign() const
Return track charge (1 or -1).
ROOT::Math::PxPyPzEVector get4Momentum() const
Getter for the 4Momentum at the closest approach of the track in the r/phi projection.
double getTransverseMomentum() const
Getter for the absolute value of the transverse momentum at the perigee.
double getZ0() const
Getter for z0.
HitPatternCDC getHitPatternCDC() const
Getter for the hit pattern in the CDC;.
Class that bundles various TrackFitResults.
Definition: Track.h:25
virtual int getNDF(void) const
Get an NDF of the fit.
Definition: KFitBase.cc:114
enum KFitError::ECode addParticle(const Particle *particle)
Add a particle to the fitter.
Definition: KFitBase.cc:59
VertexFitKFit is a derived class from KFitBase to perform vertex-constraint kinematical fit.
Definition: VertexFitKFit.h:34
double getCHIsq(void) const override
Get a chi-square of the fit.
enum KFitError::ECode doFit(void)
Perform a vertex-constraint fit.
const HepPoint3D getVertex(const int flag=KFitConst::kAfterFit) const
Get a vertex position.
Abstract base class for different kinds of events.
Temporary data structure holding the track(s) with the maximum pT.
double pLab
the momentum magnitude in lab system
double pT
the pT of the track
ROOT::Math::PxPyPzEVector p4CMS
the 4 momentum in CMS system
double clusterEnergySumLab
the sum of related cluster energies in lab system
ROOT::Math::PxPyPzEVector p4Lab
the 4 momentum in lab system
double clusterEnergySumCMS
the sum of related cluster energies in CMS system
double pCMS
the momentum magnitude in CMS system
const Track * track
the track
Temporary data structure holding the ECL clusters used for this analysis.
double energyLab
the energy in Lab system
double clusterTime
the time of the cluster
ROOT::Math::PxPyPzEVector p4CMS
the 4 momentum in CMS system
ROOT::Math::PxPyPzEVector p4Lab
the 4 momentum in lab system
const ECLCluster * cluster
The ECL cluster.
bool isTrack
is this ECL cluster likely from a track (or a photon) = is it charged?
double energyCMS
the energy in CMS system