ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/dhidas/OSUAnalysis/Tools/src/TopPairEventCandidate.cpp
Revision: 1.5
Committed: Sat Dec 31 07:50:50 2011 UTC (13 years, 4 months ago) by clseitz
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +1 -1 lines
Log Message:
all the changes

File Contents

# User Rev Content
1 dhidas 1.1 /*
2     * TopPairEventCandidate.cpp
3     *
4     * Created on: 9 Jul 2010
5     * Author: kreczko
6     */
7    
8     #include "../interface/TopPairEventCandidate.h"
9     #include <iostream>
10     #include <iomanip>
11     using namespace std;
12    
13     namespace BAT {
14    
15     const double TopPairEventCandidate::pdgWmass = 80.399;
16     const double TopPairEventCandidate::wMassWidth = 8.0; // Derived from 10% jet resolution on old jet resolution twiki page
17     const double TopPairEventCandidate::pdgTopMass = 172.9;
18     const double TopPairEventCandidate::topMassWidth = 17.0; // See above
19     // Above values from PDG 2011
20    
21     // The following are obsolete and are only retained in
22     // case the old ttbar code might be useful during
23     // testing.
24     const double TopPairEventCandidate::W_mass = TopPairEventCandidate::pdgWmass;
25     const double TopPairEventCandidate::matched_hadronic_W_mass = TopPairEventCandidate::pdgWmass;
26     const double TopPairEventCandidate::matched_hadronic_W_mass_sigma = TopPairEventCandidate::wMassWidth;
27     const double TopPairEventCandidate::matched_leptonic_top_mass = TopPairEventCandidate::pdgTopMass;
28     const double TopPairEventCandidate::matched_leptonic_top_mass_sigma = TopPairEventCandidate::topMassWidth;
29     const double TopPairEventCandidate::matched_hadronic_top_mass = TopPairEventCandidate::pdgTopMass;
30     const double TopPairEventCandidate::matched_hadronic_top_mass_sigma = TopPairEventCandidate::topMassWidth;
31     const double TopPairEventCandidate::matched_ptratio = 0.19;
32     const double TopPairEventCandidate::matched_ptratio_sigma = 0.4;
33     const double TopPairEventCandidate::matched_pt_ttbarSystem = 0.;
34     const double TopPairEventCandidate::matched_pt_ttbarSystem_sigma = 50.;
35     const double TopPairEventCandidate::matched_HTSystem = 1;
36     const double TopPairEventCandidate::matched_HTSystem_sigma = 0.1;
37     const double TopPairEventCandidate::matched_angle = 0.95;
38     const double TopPairEventCandidate::matched_angle_sigma = 0.31;
39    
40     NeutrinoSelectionCriterion::value TopPairEventCandidate::usedNeutrinoSelection; // = NeutrinoSelectionCriterion::chi2;
41     TTbarReconstructionCriterion::value TopPairEventCandidate::usedTTbarReconstruction; // = TTbarReconstructionCriterion::TopMassDifference;
42    
43    
44     TopPairEventCandidate::TopPairEventCandidate() :
45     Event(),
46     leptonFromW(),
47     leptonicBJet(),
48     hadronicBJet(),
49     jet1FromW(),
50     jet2FromW(),
51     neutrino1(),
52     neutrino2(),
53     leptonicW1(),
54     leptonicW2(),
55     hadronicW(),
56     leptonicTop1(),
57     leptonicTop2(),
58     hadronicTop(),
59     selectedNeutrino(0),
60     currentSelectedNeutrino(0),
61     hadronicBIndex(0),
62     leptonicBIndex(0),
63     jet1FromWIndex(0),
64     jet2FromWIndex(0),
65     doneReconstruction(false),
66     conversionTagger(new ConversionTagger()),
67     doneConversionTagging(false),
68     solutions(),
69     compareSolutions(){
70     }
71    
72     TopPairEventCandidate::TopPairEventCandidate(const Event& event) :
73     Event(event),
74     leptonFromW(),
75     leptonicBJet(),
76     hadronicBJet(),
77     jet1FromW(),
78     jet2FromW(),
79     neutrino1(),
80     neutrino2(),
81     leptonicW1(),
82     leptonicW2(),
83     hadronicW(),
84     leptonicTop1(),
85     leptonicTop2(),
86     hadronicTop(),
87     selectedNeutrino(0),
88     currentSelectedNeutrino(0),
89     hadronicBIndex(0),
90     leptonicBIndex(0),
91     jet1FromWIndex(0),
92     jet2FromWIndex(0),
93     doneReconstruction(false),
94     conversionTagger(new ConversionTagger()),
95     doneConversionTagging(false) {
96    
97     }
98    
99     TopPairEventCandidate::~TopPairEventCandidate() {
100     }
101    
102     bool TopPairEventCandidate::passesScrapingFilter() const {
103     if (tracks.size() > 10) {
104     if (numberOfHighPurityTracks / (1.0 * tracks.size()) > 0.25)
105     return true;
106     else
107     return false;
108     } else
109     return isBeamScraping == false;
110     }
111    
112     bool TopPairEventCandidate::passesHighLevelTrigger() const {
113     if (isRealData()) {
114 clseitz 1.3 bool trigOn = false;
115 dhidas 1.1 if (runNumber < 140041)
116     return HLT(HLTriggers::HLT_Ele10_LW_L1R);
117     else if (runNumber >= 140041 && runNumber <= 143962)
118     return HLT(HLTriggers::HLT_Ele15_SW_L1R);
119     else if (runNumber > 143962 && runNumber <= 146427)
120     return HLT(HLTriggers::HLT_Ele15_SW_CaloEleId_L1R);
121     else if (runNumber > 146427 && runNumber <= 147116)
122     return HLT(HLTriggers::HLT_Ele17_SW_CaloEleId_L1R);
123     else if (runNumber > 147116 && runNumber <= 148818)
124     return HLT(HLTriggers::HLT_Ele17_SW_TightEleId_L1R);
125     else if (runNumber >= 148819 && runNumber < 149181)
126     return HLT(HLTriggers::HLT_Ele22_SW_TighterEleId_L1R);
127     //return HLT(HLTriggers::HLT_Ele22_SW_TighterEleId_L1R_v2);
128     else if(runNumber >= 149181 && runNumber < 160000)
129     return HLT(HLTriggers::HLT_Ele22_SW_TighterEleId_L1R);
130     //return HLT(HLTriggers::HLT_Ele22_SW_TighterEleId_L1R_v3);
131 clseitz 1.2
132 clseitz 1.3 else if (runNumber >= 160404 && runNumber <= 163869)
133     trigOn = HLT(HLTriggers::HLT_Ele27_CaloIdVT_CaloIsoT_TrkIdT_TrkIsoT);
134     /*else if (runNumber >= 165970 && runNumber <= 166346)
135     trigOn = HLT(HLTriggers::HLT_Ele32_CaloIdVT_CaloIsoT_TrkIdT_TrkIsoT);*/
136     else if (runNumber >= 165970 && runNumber <= 178380)
137     trigOn =
138     HLT(HLTriggers::HLT_Ele25_CaloIdVT_CaloIsoT_TrkIdT_TrkIsoT_TriCentralJet30);
139     else if (runNumber >= 178420)
140     trigOn =
141     HLT(HLTriggers::HLT_Ele25_CaloIdVT_CaloIsoT_TrkIdT_TrkIsoT_TriCentralPFJet30);
142     if (trigOn)
143     return (true);
144     // Now try muon triggers if electron triggers failed
145 clseitz 1.4 /* else if ((runNumber >= 160404 && runNumber <= 163869) ||
146 clseitz 1.3 (runNumber >= 165088 && runNumber <= 166967))
147     return (HLT(HLTriggers::HLT_Mu30) || HLT(HLTriggers::HLT_IsoMu17));
148     else if (runNumber >= 167039 && runNumber <= 167913)
149     return (HLT(HLTriggers::HLT_IsoMu17_eta2p1) ||
150     HLT(HLTriggers::HLT_IsoMu24));
151     else if (runNumber >= 170249 && runNumber <= 173198)
152 clseitz 1.4 return (HLT(HLTriggers::HLT_Mu40)||HLT(HLTriggers::HLT_Mu30) || HLT(HLTriggers::HLT_IsoMu24));
153 clseitz 1.3 else if (runNumber >= 173236 && runNumber <= 173692)
154 clseitz 1.4 return (HLT(HLTriggers::HLT_Mu40_eta2p1) || HLT(HLTriggers::HLT_IsoMu20));
155 clseitz 1.3 else if (runNumber >= 175860 && runNumber <= 178160)
156 clseitz 1.4 return ((HLT(HLTriggers::HLT_Mu40_eta2p1) || HLT(HLTriggers::HLT_IsoMu24_eta2p1));
157 clseitz 1.3 else if (runNumber >= 178162)
158 clseitz 1.4 return (HLT(HLTriggers::HLT_IsoMu30_eta2p1) || (HLT(HLTriggers::HLT_Mu40_eta2p1));*/
159     else if (runNumber >= 160404)
160     return (HLT(HLTriggers::HLT_IsoMu24_eta2p1) || HLT(HLTriggers::HLT_IsoMu24));
161     else return false;
162 clseitz 1.5 } else return (HLT(HLTriggers::HLT_IsoMu24));// || HLT(HLTriggers::HLT_Ele32_CaloIdVT_CaloIsoT_TrkIdT_TrkIsoT) || HLT(HLTriggers::HLT_Ele27_CaloIdVT_CaloIsoT_TrkIdT_TrkIsoT)); // do not use HLT for MC
163 dhidas 1.1 }
164    
165     bool TopPairEventCandidate::hasOneGoodPrimaryVertex() const {
166     return goodVertices.size() >= 1;
167     }
168    
169     bool TopPairEventCandidate::hasOnlyOneGoodIsolatedElectron() const {
170     if(Event::usePFIsolation)
171     return goodPFIsolatedElectrons.size() == 1;
172     else
173     return goodIsolatedElectrons.size() == 1;
174     }
175    
176     bool TopPairEventCandidate::isolatedElectronDoesNotComeFromConversion() const {
177     bool passConversion = false;
178     if (Event::usePFIsolation) {
179     if (goodPFIsolatedElectrons.size() > 0)
180     passConversion = goodPFIsolatedElectrons.front()->isFromConversion() == false;
181     } else {
182     if (goodIsolatedElectrons.size() > 0)
183     passConversion = goodIsolatedElectrons.front()->isFromConversion() == false;
184     }
185    
186     return passConversion;
187     }
188    
189     bool TopPairEventCandidate::isolatedElectronNotTaggedAsFromConversion() const {
190     bool passConversion = false;
191     ElectronPointer electron;
192     if (Event::usePFIsolation) {
193     if (goodPFIsolatedElectrons.size() > 0)
194     electron = goodPFIsolatedElectrons.front();
195     } else {
196     if (goodIsolatedElectrons.size() > 0)
197     electron = goodIsolatedElectrons.front();
198     }
199     if (electron != 0) {
200     if (useCustomConversionTagger) {
201     conversionTagger->calculateConversionVariables(electron, tracks, 3.8, 0.45);
202     passConversion = conversionTagger->isFromConversion(0.02, 0.02) == false;
203     } else {
204     passConversion = electron->isTaggedAsConversion(0.02, 0.02) == false;
205     }
206     }
207    
208     return passConversion;
209     }
210    
211     bool TopPairEventCandidate::hasNoIsolatedMuon() const {
212     return looseMuons.size() == 0;
213     }
214    
215     bool TopPairEventCandidate::hasAtLeastOneGoodJet() const {
216     return goodJets.size() >= 1;
217     }
218    
219     bool TopPairEventCandidate::hasAtLeastTwoGoodJets() const {
220     return goodJets.size() >= 2;
221     }
222    
223     bool TopPairEventCandidate::hasAtLeastThreeGoodJets() const {
224     return goodJets.size() >= 3;
225     }
226    
227     bool TopPairEventCandidate::hasAtLeastFourGoodJets() const {
228     return goodJets.size() >= 4;
229     }
230    
231     bool TopPairEventCandidate::isNotAZBosonEvent() const {
232     float invariantMass = 0;
233     bool isZEvent = false;
234     ElectronPointer isoElectron;
235    
236     if (Event::usePFIsolation && goodPFIsolatedElectrons.size() > 0)
237     isoElectron = goodPFIsolatedElectrons.front();
238     else if (goodIsolatedElectrons.size() > 0)
239     isoElectron = goodIsolatedElectrons.front();
240    
241     if (isoElectron != NULL && allElectrons.size() > 1) {
242     for (unsigned int index = 0; index < allElectrons.size(); ++index) {
243     const ElectronPointer looseElectron = allElectrons.at(index);
244     bool passLooseIso = false;
245    
246     if (Event::usePFIsolation)
247     passLooseIso = looseElectron->isLoose() && looseElectron->pfIsolation() < 1.;
248     else
249     passLooseIso = looseElectron->isLoose() && looseElectron->relativeIsolation() < 1.;
250    
251     if (passLooseIso)
252     invariantMass = isoElectron->invariantMass(looseElectron);
253     else
254     invariantMass = 0;
255    
256     bool passesLowerLimit = invariantMass > 76;
257     bool passesUpperLimit = invariantMass < 106;
258     if (passesLowerLimit && passesUpperLimit)
259     isZEvent = true;
260     }
261    
262     }
263    
264    
265     return isZEvent == false;
266     }
267    
268     bool TopPairEventCandidate::passesMETCut() const{
269     return met->et() > 20.;
270     }
271    
272     bool TopPairEventCandidate::passesAsymmetricJetCuts() const {
273     if(goodJets.size() < 2)// good jets have a cut of 30 GeV!
274     return false;
275     JetPointer leadingJet = goodJets.front();
276     JetPointer secondLeadingJet = goodJets.at(1);
277     return leadingJet->pt() > 70 && secondLeadingJet->pt() > 50;
278    
279     }
280    
281     bool TopPairEventCandidate::hasAtLeastOneBtag() const {
282     return goodBJets.size() >= 1;
283     }
284    
285     bool TopPairEventCandidate::hasAtLeastTwoBtags() const{
286     return goodBJets.size() >= 2;
287     }
288    
289     bool TopPairEventCandidate::passesFullTTbarEPlusJetSelection() const {
290     // unsigned int newstep = (int) TTbarEPlusJetsSelection::NUMBER_OF_SELECTION_STEPS - 1;
291     ///////////////////////////// from Lucaz
292     return passesSelectionStepUpTo(TTbarEPlusJetsSelection::AtLeastFourGoodJets);//(TTbarEPlusJetsSelection::Step) newstep);
293     //
294     }
295    
296     bool TopPairEventCandidate::passesSelectionStepUpTo(enum TTbarEPlusJetsSelection::Step step) const {
297     if (step == TTbarEPlusJetsSelection::FilterOutScraping)
298     return passesSelectionStep(step);
299     else {
300     unsigned int newstep = (int) step - 1;
301     return passesSelectionStep(step) && passesSelectionStepUpTo((TTbarEPlusJetsSelection::Step) newstep);
302     }
303     }
304    
305     bool TopPairEventCandidate::passesNMinus1(enum TTbarEPlusJetsSelection::Step omitted) const {
306     bool passes(true);
307    
308     for (unsigned int cut = 0; cut < TTbarEPlusJetsSelection::NUMBER_OF_SELECTION_STEPS; ++cut) {
309     if (cut == (unsigned int) omitted)
310     continue;
311     passes = passes && passesSelectionStep((TTbarEPlusJetsSelection::Step) cut);
312     }
313     return passes;
314     }
315    
316     bool TopPairEventCandidate::passesSelectionStep(enum TTbarEPlusJetsSelection::Step step) const {
317     switch (step) {
318     case TTbarEPlusJetsSelection::FilterOutScraping:
319     return passesScrapingFilter();
320     case TTbarEPlusJetsSelection::HighLevelTrigger:
321     return passesHighLevelTrigger();
322     case TTbarEPlusJetsSelection::GoodPrimaryvertex:
323     return hasOneGoodPrimaryVertex();
324     case TTbarEPlusJetsSelection::OneIsolatedElectron:
325     return hasOnlyOneGoodIsolatedElectron();
326     case TTbarEPlusJetsSelection::ConversionRejection:
327     return isolatedElectronDoesNotComeFromConversion();
328     case TTbarEPlusJetsSelection::ConversionFinder:
329     return isolatedElectronNotTaggedAsFromConversion();
330     case TTbarEPlusJetsSelection::LooseMuonVeto:
331     return hasNoIsolatedMuon();
332     case TTbarEPlusJetsSelection::AtLeastOneGoodJets:
333     return hasAtLeastOneGoodJet();
334     case TTbarEPlusJetsSelection::AtLeastTwoGoodJets:
335     return hasAtLeastTwoGoodJets();
336     case TTbarEPlusJetsSelection::AtLeastThreeGoodJets:
337     return hasAtLeastThreeGoodJets();
338     case TTbarEPlusJetsSelection::AtLeastFourGoodJets:
339     return hasAtLeastFourGoodJets();
340     case TTbarEPlusJetsSelection::Zveto:
341     return isNotAZBosonEvent();
342     case TTbarEPlusJetsSelection::MissingTransverseEnergy:
343     return passesMETCut();
344     case TTbarEPlusJetsSelection::AsymmetricJetCuts:
345     return passesAsymmetricJetCuts();
346     case TTbarEPlusJetsSelection::AtLeastOneBtag:
347     return hasAtLeastOneBtag();
348     case TTbarEPlusJetsSelection::AtLeastTwoBtags:
349     return hasAtLeastTwoBtags();
350     default:
351     return false;
352     }
353     }
354    
355     bool TopPairEventCandidate::passesRelIsoSelection() const{
356     bool passesFirst3 = passesSelectionStepUpTo(TTbarEPlusJetsSelection::GoodPrimaryvertex);
357     bool passGoodElectrons = goodElectrons.size() > 0 && goodIsolatedElectrons.size() < 2;
358     bool passesBothIsolationvetos = false;
359     if (passGoodElectrons) {
360     const ElectronPointer electron = MostIsolatedElectron();
361     if (electron->isGood()) {
362     if (useCustomConversionTagger) {
363     conversionTagger->calculateConversionVariables(electron, tracks, 3.8, 0.45);
364     passesBothIsolationvetos = electron->isFromConversion() == false && conversionTagger->isFromConversion(
365     0.02, 0.02) == false;
366     }
367     else{
368     passesBothIsolationvetos = electron->isFromConversion() == false && electron->isTaggedAsConversion(
369     0.02, 0.02) == false;
370     }
371     }
372    
373     }
374     bool muonVeto = hasNoIsolatedMuon();
375     bool Zveto = isNotAZBosonEvent();
376     return passesFirst3 && passGoodElectrons && passesBothIsolationvetos && muonVeto && Zveto;
377     }
378    
379     bool TopPairEventCandidate::passesRelIsoControlSelection() const{
380     bool passesFirst3 = passesSelectionStepUpTo(TTbarEPlusJetsSelection::GoodPrimaryvertex);
381     bool passGoodElectrons = allElectrons.size() > 0 && goodIsolatedElectrons.size() < 2;
382     bool passesBothIsolationvetos = false;
383     if (passGoodElectrons) {
384     const ElectronPointer electron = MostIsolatedElectron();
385     if (electron->isQCDElectron()) {
386     if (useCustomConversionTagger) {
387     conversionTagger->calculateConversionVariables(electron, tracks, 3.8, 0.45);
388     passesBothIsolationvetos = electron->isFromConversion() == false && conversionTagger->isFromConversion(
389     0.02, 0.02) == false;
390     } else {
391     passesBothIsolationvetos = electron->isFromConversion() == false && electron->isTaggedAsConversion(
392     0.02, 0.02) == false;
393     }
394     }
395    
396     }
397     bool muonVeto = hasNoIsolatedMuon();
398     bool Zveto = isNotAZBosonEvent();
399     return passesFirst3 && passGoodElectrons && passesBothIsolationvetos && muonVeto && Zveto;
400     }
401    
402     bool TopPairEventCandidate::passesPFIsoSelection() const{
403     bool passesFirst3 = passesSelectionStepUpTo(TTbarEPlusJetsSelection::GoodPrimaryvertex);
404     bool passGoodElectrons = goodElectrons.size() > 0 && goodPFIsolatedElectrons.size() < 2;
405     bool passesBothIsolationvetos = false;
406     if (passGoodElectrons) {
407     const ElectronPointer electron = MostPFIsolatedElectron();
408     if (electron->isGood()) {
409     if (useCustomConversionTagger) {
410     conversionTagger->calculateConversionVariables(electron, tracks, 3.8, 0.45);
411     passesBothIsolationvetos = electron->isFromConversion() == false && conversionTagger->isFromConversion(
412     0.02, 0.02) == false;
413     }
414     else{
415     passesBothIsolationvetos = electron->isFromConversion() == false && electron->isTaggedAsConversion(
416     0.02, 0.02) == false;
417     }
418     }
419    
420     }
421     bool muonVeto = hasNoIsolatedMuon();
422     bool Zveto = isNotAZBosonEvent();
423     return passesFirst3 && passGoodElectrons && passesBothIsolationvetos && muonVeto && Zveto;
424     }
425    
426     bool TopPairEventCandidate::passesPFIsoControlSelection() const{
427     bool passesFirst3 = passesSelectionStepUpTo(TTbarEPlusJetsSelection::GoodPrimaryvertex);
428     bool passGoodElectrons = allElectrons.size() > 0 && goodPFIsolatedElectrons.size() < 2;
429     bool passesBothIsolationvetos = false;
430     if (passGoodElectrons) {
431     const ElectronPointer electron = MostPFIsolatedElectron();
432     if (electron->isQCDElectron()) {
433     if (useCustomConversionTagger) {
434     conversionTagger->calculateConversionVariables(electron, tracks, 3.8, 0.45);
435     passesBothIsolationvetos = electron->isFromConversion() == false && conversionTagger->isFromConversion(
436     0.02, 0.02) == false;
437     } else {
438     passesBothIsolationvetos = electron->isFromConversion() == false && electron->isTaggedAsConversion(
439     0.02, 0.02) == false;
440     }
441     }
442    
443     }
444     bool muonVeto = hasNoIsolatedMuon();
445     bool Zveto = isNotAZBosonEvent();
446     return passesFirst3 && passGoodElectrons && passesBothIsolationvetos && muonVeto && Zveto;
447     }
448    
449     bool TopPairEventCandidate::passesConversionSelection() const {
450     bool passesFirst6 = passesSelectionStepUpTo(TTbarEPlusJetsSelection::Zveto);
451     bool isConversion1 = isolatedElectronDoesNotComeFromConversion() == false;
452     bool isConversion2 = isolatedElectronNotTaggedAsFromConversion() == false;
453     bool atLeast4Jets = hasAtLeastFourGoodJets();
454     return passesFirst6 && (isConversion1 || isConversion2) && atLeast4Jets;
455     }
456    
457     bool TopPairEventCandidate::passesAntiIsolationSelection() const {
458     //require at least one good electron and no isolated good electrons
459     if (!(goodElectrons.size() > 0 && goodIsolatedElectrons.size() == 0))
460     return false;
461    
462     bool passesFirst3 = passesSelectionStep(TTbarEPlusJetsSelection::GoodPrimaryvertex);
463    
464    
465     bool muonVeto = passesSelectionStep(TTbarEPlusJetsSelection::LooseMuonVeto);
466     bool zveto = passesSelectionStep(TTbarEPlusJetsSelection::Zveto);
467     bool conversionVeto = (goodElectrons.front()->isFromConversion() || goodElectrons.front()->isTaggedAsConversion(
468     0.2, 0.2)) == false;
469     bool jets = hasAtLeastFourGoodJets();
470     return passesFirst3 && muonVeto && zveto && conversionVeto && jets;
471     }
472    
473     void TopPairEventCandidate::reconstructTTbar(LeptonPointer lepton) {
474     if (goodJets.size() < 4)
475     throw ReconstructionException("Not enough jets available to reconstruct top event using Mass Equality method.");
476     leptonFromW = lepton;
477     selectedNeutrino = 0;
478     currentSelectedNeutrino = 0;
479     reconstructNeutrinos();
480     double chosen_TopMassDifference(9999999.);
481     double chosen_Chi2Total(9999999.);
482    
483     for (unsigned short hadBindex = 0; hadBindex < goodJets.size(); ++hadBindex) {
484     for (unsigned short lepBindex = 0; lepBindex < goodJets.size(); ++lepBindex) {
485     if (lepBindex == hadBindex)
486     continue;
487     for (unsigned short jet1Index = 0; jet1Index < goodJets.size(); ++jet1Index) {
488     if (jet1Index == lepBindex || jet1Index == hadBindex)
489     continue;
490     for (unsigned short jet2Index = 0; jet2Index < goodJets.size(); ++jet2Index) {
491     if (jet2Index == jet1Index || jet2Index == lepBindex || jet2Index == hadBindex)
492     continue;
493     hadronicBJet = goodJets.at(hadBindex);
494     leptonicBJet = goodJets.at(lepBindex);
495     jet1FromW = goodJets.at(jet1Index);
496     jet2FromW = goodJets.at(jet2Index);
497    
498     leptonicW1 = ParticlePointer(new Particle(*neutrino1 + *leptonFromW));
499     leptonicW2 = ParticlePointer(new Particle(*neutrino2 + *leptonFromW));
500     hadronicW = ParticlePointer(new Particle(*jet1FromW + *jet2FromW));
501     leptonicTop1 = ParticlePointer(new Particle(*leptonicBJet + *leptonicW1));
502     leptonicTop2 = ParticlePointer(new Particle(*leptonicBJet + *leptonicW2));
503     hadronicTop = ParticlePointer(new Particle(*hadronicBJet + *hadronicW));
504     fillHypotheses();
505     selectNeutrinoSolution();
506     double TopMassDifference = calculateTopMassDifference(currentSelectedNeutrino);
507     double chi2 = getTotalChi2(currentSelectedNeutrino);
508     switch (usedTTbarReconstruction) {
509     case TTbarReconstructionCriterion::TopMassDifference:
510     if (TopMassDifference < chosen_TopMassDifference) {
511     hadronicBIndex = hadBindex;
512     leptonicBIndex = lepBindex;
513     jet1FromWIndex = jet1Index;
514     jet2FromWIndex = jet2Index;
515     chosen_TopMassDifference = TopMassDifference;
516     selectedNeutrino = currentSelectedNeutrino;
517     }
518     break;
519    
520     case TTbarReconstructionCriterion::chi2:
521     if (chi2 < chosen_Chi2Total) {
522     hadronicBIndex = hadBindex;
523     leptonicBIndex = lepBindex;
524     jet1FromWIndex = jet1Index;
525     jet2FromWIndex = jet2Index;
526     chosen_Chi2Total = chi2;
527     selectedNeutrino = currentSelectedNeutrino;
528     }
529     break;
530     }
531     }
532     }
533     }
534     }
535     std::sort(solutions.begin(), solutions.end(), compareSolutions);
536     hadronicBJet = goodJets.at(hadronicBIndex);
537     leptonicBJet = goodJets.at(leptonicBIndex);
538     jet1FromW = goodJets.at(jet1FromWIndex);
539     jet2FromW = goodJets.at(jet2FromWIndex);
540     leptonicW1 = ParticlePointer(new Particle(*neutrino1 + *leptonFromW));
541     leptonicW2 = ParticlePointer(new Particle(*neutrino2 + *leptonFromW));
542     hadronicW = ParticlePointer(new Particle(*jet1FromW + *jet2FromW));
543     leptonicTop1 = ParticlePointer(new Particle(*leptonicBJet + *leptonicW1));
544     leptonicTop2 = ParticlePointer(new Particle(*leptonicBJet + *leptonicW2));
545     hadronicTop = ParticlePointer(new Particle(*hadronicBJet + *hadronicW));
546     if (selectedNeutrino == 1)
547     ttbarResonance = ParticlePointer(new Particle(*leptonicTop1 + *hadronicTop));
548     else
549     ttbarResonance = ParticlePointer(new Particle(*leptonicTop2 + *hadronicTop));
550     doneReconstruction = true;
551     }
552    
553    
554     void TopPairEventCandidate::reconstructNeutrinos() {
555     boost::array<double, 2> neutrinoPzs = computeNeutrinoPz();
556     double energy1 = sqrt(met->et() * met->et() + neutrinoPzs.at(0) * neutrinoPzs.at(0));
557     double energy2 = sqrt(met->et() * met->et() + neutrinoPzs.at(1) * neutrinoPzs.at(1));
558     neutrino1 = ParticlePointer(new Particle(energy1, met->px(), met->py(), neutrinoPzs.at(0)));
559     neutrino2 = ParticlePointer(new Particle(energy2, met->px(), met->py(), neutrinoPzs.at(1)));
560    
561     if (isnan(neutrino1->energy()) && isnan(neutrino2->energy()))
562     throw ReconstructionException("No physical neutrino solution found");
563     else if (isnan(neutrino1->energy()))
564     neutrino1 = neutrino2;
565     else if (isnan(neutrino2->energy()))
566     neutrino2 = neutrino1;
567     }
568    
569     const boost::array<double, 2> TopPairEventCandidate::computeNeutrinoPz() {
570     if (leptonFromW == 0)
571     throw ReconstructionException("Could not reconstruct neutrinos: no isolated leptons found");
572     if (met->energy() == 0)
573     throw ReconstructionException("Could not reconstruct neutrinos: no MET found");
574     boost::array<double, 2> neutrinoPzs;
575    
576     // Two unknowns, neutrino E and pz. But since neutrino mass = 0, can
577     // solve for pz. Result is long and messy, as follows.
578    
579     double pz1(0), pz2(0);
580     double ee = leptonFromW->energy();
581     double pxe = leptonFromW->px();
582     double pye = leptonFromW->py();
583     double pze = leptonFromW->pz();
584     double pxnu = met->px();
585     double pynu = met->py();
586    
587     double a = W_mass * W_mass + 2.0 * pxe * pxnu + 2.0 * pye * pynu;
588     double A = 4.0 * (ee * ee - pze * pze);
589     double B = -4.0 * a * pze;
590     double C = 4.0 * ee * ee * (pxnu * pxnu + pynu * pynu) - a * a;
591    
592     double tmproot = B * B - 4.0 * A * C;
593     if (tmproot < 0) {
594     pz1 = pz2 = -B / (2 * A); // Take real part
595     } else {
596     pz1 = (-B + TMath::Sqrt(tmproot)) / (2.0 * A);
597     pz2 = (-B - TMath::Sqrt(tmproot)) / (2.0 * A);
598    
599     }
600     neutrinoPzs[0] = pz1;
601     neutrinoPzs[1] = pz2;
602     return neutrinoPzs;
603     }
604    
605    
606     void TopPairEventCandidate::fillHypotheses() {
607     TtbarHypothesisPointer hypothesis1(fillHypothesis(1));
608     TtbarHypothesisPointer hypothesis2(fillHypothesis(2));
609     solutions.push_back(hypothesis1);
610     solutions.push_back(hypothesis2);
611    
612     }
613    
614     const TtbarHypothesisPointer TopPairEventCandidate::fillHypothesis(unsigned short int neutrinoSolution) {
615     TtbarHypothesisPointer hypothesis(new TtbarHypothesis());
616     hypothesis->leptonFromW = leptonFromW;
617     hypothesis->leptonicBjet = leptonicBJet;
618     hypothesis->hadronicBJet = hadronicBJet;
619     hypothesis->jet1FromW = jet1FromW;
620     hypothesis->jet2FromW = jet2FromW;
621     hypothesis->hadronicW = hadronicW;
622     hypothesis->hadronicTop = hadronicTop;
623     hypothesis->hadronicChi2 = getHadronicChi2();
624     if(neutrinoSolution == 1) {
625     hypothesis->neutrinoFromW = neutrino1;
626     hypothesis->leptonicW = leptonicW1;
627     hypothesis->leptonicTop = leptonicTop1;
628     }
629     else {
630     hypothesis->neutrinoFromW = neutrino2;
631     hypothesis->leptonicW = leptonicW2;
632     hypothesis->leptonicTop = leptonicTop2;
633     }
634    
635     hypothesis->totalChi2 = getTotalChi2(neutrinoSolution);
636     hypothesis->globalChi2 = getGlobalChi2(neutrinoSolution);
637     hypothesis->leptonicChi2 = getLeptonicChi2(neutrinoSolution);
638     ParticlePointer resonance(new Particle(*hypothesis->leptonicTop + *hypothesis->hadronicTop));
639     hypothesis->resonance = resonance;
640     return hypothesis;
641     }
642    
643     void TopPairEventCandidate::selectNeutrinoSolution() {
644    
645     if (leptonicTop1->mass() < 0 && leptonicTop2->mass() < 0) {
646     inspectReconstructedEvent();
647     throw ReconstructionException("No valid neutrino solution found");
648     } else if (leptonicTop1->mass() < 0 && leptonicTop2->mass() > 0) {
649     currentSelectedNeutrino = 2;
650     } else if (leptonicTop1->mass() > 0 && leptonicTop2->mass() < 0) {
651     currentSelectedNeutrino = 1;
652     } else {// both solutions give positive mass
653     switch (usedNeutrinoSelection) {
654     case NeutrinoSelectionCriterion::TopMassDifference:
655     fabs(leptonicTop1->mass()-hadronicTop->mass()) < fabs(leptonicTop2->mass()-hadronicTop->mass()) ?
656     currentSelectedNeutrino = 1 : currentSelectedNeutrino = 2;
657     break;
658     case NeutrinoSelectionCriterion::chi2:
659     getTotalChi2(1) < getTotalChi2(2) ? currentSelectedNeutrino = 1 : currentSelectedNeutrino = 2;
660     break;
661    
662     case NeutrinoSelectionCriterion::pzClosestToLepton:
663     fabs(neutrino1->pz() - leptonFromW->pz()) < fabs(neutrino2->pz()
664     - leptonFromW->pz()) ? currentSelectedNeutrino = 1 : currentSelectedNeutrino = 2;
665     break;
666    
667     case NeutrinoSelectionCriterion::mostCentral:
668     fabs(neutrino1->pz()) < fabs(neutrino2->pz()) ? currentSelectedNeutrino = 1 : currentSelectedNeutrino = 2;
669     break;
670    
671     case NeutrinoSelectionCriterion::pzClosestToLeptonOrMostcentralIfAbove300:
672     fabs(neutrino1->pz() - leptonFromW->pz()) < fabs(neutrino2->pz()
673     - leptonFromW->pz()) ? currentSelectedNeutrino = 1 : currentSelectedNeutrino = 2;
674     if (fabs(neutrino1->pz()) > 300 || fabs(neutrino2->pz()) > 300)
675     fabs(neutrino1->pz()) < fabs(neutrino2->pz()) ? currentSelectedNeutrino = 1 : currentSelectedNeutrino
676     = 2;
677     break;
678    
679     case NeutrinoSelectionCriterion::largestValueOfCosine:
680     TVector3 p3W, p3e;
681     //TODO clean up
682     p3W = leptonicW1->getFourVector().Vect();
683     p3e = leptonFromW->getFourVector().Vect();
684    
685     double sinthcm1 = 2. * (p3e.Perp(p3W)) / W_mass;
686     p3W = leptonicW2->getFourVector().Vect();
687     double sinthcm2 = 2. * (p3e.Perp(p3W)) / W_mass;
688    
689     double costhcm1 = TMath::Sqrt(1. - sinthcm1 * sinthcm1);
690     double costhcm2 = TMath::Sqrt(1. - sinthcm2 * sinthcm2);
691     costhcm1 > costhcm2 ? currentSelectedNeutrino = 1 : currentSelectedNeutrino = 2;
692     break;
693    
694     }
695     }
696    
697     }
698    
699     double TopPairEventCandidate::calculateTopMassDifference(unsigned short int neutrinoSolution) const {
700    
701     double LeptonicTop1MassDifference = fabs(leptonicTop1->mass()-hadronicTop->mass());
702     double LeptonicTop2MassDifference = fabs(leptonicTop2->mass()-hadronicTop->mass());
703    
704     if (neutrinoSolution == 1)
705     return LeptonicTop1MassDifference;
706     else
707     return LeptonicTop2MassDifference;
708    
709     }
710    
711     double TopPairEventCandidate::getTotalChi2() {
712     double totalChi2(9999999);
713     double firstTotalChi2 = getTotalChi2(1);
714     double secondTotalChi2 = getTotalChi2(2);
715     selectedNeutrino == 1 ? totalChi2 = firstTotalChi2 : totalChi2 = secondTotalChi2;
716     // if (firstTotalChi2 < secondTotalChi2) {
717     // selectedNeutrino = 1;
718     // totalChi2 = firstTotalChi2;
719     // } else {
720     // selectedNeutrino = 2;
721     // totalChi2 = secondTotalChi2;
722     // }
723     return totalChi2;
724     }
725    
726     double TopPairEventCandidate::getTotalChi2(unsigned short int neutrinoSolution) const {
727     return getLeptonicChi2(neutrinoSolution) + getHadronicChi2() + getGlobalChi2(neutrinoSolution);
728     }
729    
730     double TopPairEventCandidate::getLeptonicChi2(unsigned short int neutrinoSolution) const {
731     double topMass(0);
732     double angle = leptonicBJet->angle(leptonFromW);
733     if (neutrinoSolution == 1)
734     topMass = leptonicTop1->mass();
735     else
736     topMass = leptonicTop2->mass();
737    
738     return getLeptonicChi2(topMass, angle);
739     }
740    
741     double TopPairEventCandidate::getLeptonicChi2(double topMass, double angle) const {
742     cout << "Using old TTBar getLeptonicChi2 \n";
743     double massDifference = TMath::Power(topMass - matched_leptonic_top_mass, 2);
744     double massError = 2 * matched_leptonic_top_mass_sigma * matched_leptonic_top_mass_sigma;
745     double massTerm = massDifference / massError;
746    
747     double angleDifference = TMath::Power(angle - matched_angle, 2);
748     double angleError = 2 * matched_angle_sigma * matched_angle_sigma;
749     double angleTerm = angleDifference / angleError;
750     return 1.0 / sqrt(2.0) * (angleTerm + massTerm);
751     }
752    
753     double TopPairEventCandidate::getHadronicChi2() const {
754     double ptRatioDifference = TMath::Power(PtRatio() - matched_ptratio, 2);
755     double ptRatioError = 2 * matched_ptratio_sigma * matched_ptratio_sigma;
756     double ptRatioTerm = ptRatioDifference / ptRatioError;
757    
758     double WmassDifference = TMath::Power(hadronicW->mass() - matched_hadronic_W_mass, 2);
759     double WmassError = 2 * matched_hadronic_W_mass_sigma * matched_hadronic_W_mass_sigma;
760     double WmassTerm = WmassDifference / WmassError;
761    
762     double topMassDifference = TMath::Power(hadronicTop->mass() - matched_hadronic_top_mass, 2);
763     double topMassError = 2 * matched_hadronic_top_mass_sigma * matched_hadronic_top_mass_sigma;
764     double topMassTerm = topMassDifference / topMassError;
765     return 1 / sqrt(3) * (topMassTerm + WmassTerm + ptRatioTerm);
766    
767     ///////////////////////////// Latest Bristol code may have dropped ptRatioTerm
768     // return 1 / sqrt(2) * (topMassTerm + WmassTerm);// + ptRatioTerm);
769     //
770     }
771    
772     double TopPairEventCandidate::PtRatio() const {
773     return TMath::Log(hadronicTop->pt() / hadronicW->pt());
774     }
775    
776     double TopPairEventCandidate::getGlobalChi2(unsigned short neutrinoSolution) const {
777     double pttbar = PtTtbarSystem(neutrinoSolution);
778     double pttbarDifference = TMath::Power(pttbar - matched_pt_ttbarSystem, 2);
779     double pttbarError = (2 * matched_pt_ttbarSystem_sigma * matched_pt_ttbarSystem_sigma);
780     double pttbarTerm = pttbarDifference / pttbarError;
781    
782     double htSystemDifference = TMath::Power(HTSystem() - matched_HTSystem, 2);
783     double htSystemError = matched_HTSystem_sigma * matched_HTSystem_sigma * 2;
784     double htSystemTerm = htSystemDifference / htSystemError;
785     return 1 / sqrt(2) * (pttbarTerm + htSystemTerm);
786     }
787    
788     double TopPairEventCandidate::PtTtbarSystem(unsigned short neutrinoSolution) const {
789     ParticlePointer combined;
790     if (neutrinoSolution == 1)
791     combined = ParticlePointer(new Particle(*leptonicTop1 + *hadronicTop));
792     else
793     combined = ParticlePointer(new Particle(*leptonicTop2 + *hadronicTop));
794     return combined->pt();
795     }
796    
797     double TopPairEventCandidate::HT(unsigned short jetLimit) const {
798     double HT(0);
799     unsigned short limit = goodJets.size();
800     if (limit > jetLimit + 1)
801     limit = jetLimit + 1;
802    
803     for (unsigned short index = 0; index < limit; ++index)
804     HT += goodJets.at(index)->pt();
805    
806     return HT;
807     }
808    
809     double TopPairEventCandidate::HTSystem() const {
810     return sumPt() / HT(8);
811     }
812    
813     double TopPairEventCandidate::sumPt() const {
814     return leptonicBJet->pt() + hadronicBJet->pt() + jet1FromW->pt() + jet2FromW->pt();
815     }
816    
817     void TopPairEventCandidate::throwExpeptionIfNotReconstructed(TString location) const {
818     if (doneReconstruction == false)
819     throw ReconstructionException(TString("Can't access reconstructed particles before reconstruction: ") + location);
820     }
821    
822     const LeptonPointer TopPairEventCandidate::getLeptonFromWDecay() const {
823     return leptonFromW;
824     }
825    
826     const ParticlePointer TopPairEventCandidate::getNeutrinoFromWDecay() const {
827     throwExpeptionIfNotReconstructed("TopPairEventCandidate::getNeutrinoFromWDecay");
828     if (selectedNeutrino == 1)
829     return neutrino1;
830     else
831     return neutrino2;
832     }
833    
834     const JetPointer TopPairEventCandidate::getHadronicBJet() const {
835     throwExpeptionIfNotReconstructed("TopPairEventCandidate::getHadronicBJet");
836     return hadronicBJet;
837     }
838    
839     const JetPointer TopPairEventCandidate::getLeptonicBJet() const {
840     throwExpeptionIfNotReconstructed("TopPairEventCandidate::getLeptonicBJet");
841     return leptonicBJet;
842     }
843    
844    
845     const ParticlePointer TopPairEventCandidate::getLeptonicW() const
846     {
847     throwExpeptionIfNotReconstructed("TopPairEventCandidate::getLeptonicW");
848     if (selectedNeutrino == 1)
849     return leptonicW1;
850     else
851     return leptonicW2;
852     }
853    
854    
855     const JetPointer TopPairEventCandidate::getJet1FromHadronicW() const {
856     throwExpeptionIfNotReconstructed("TopPairEventCandidate::getJet1FromHadronicW");
857     return jet1FromW;
858     }
859    
860     const JetPointer TopPairEventCandidate::getJet2FromHadronicW() const {
861     throwExpeptionIfNotReconstructed("TopPairEventCandidate::getJet2FromHadronicW");
862     return jet2FromW;
863     }
864    
865     const ParticlePointer TopPairEventCandidate::getHadronicW() const {
866     throwExpeptionIfNotReconstructed("TopPairEventCandidate::getHadronicW");
867     return hadronicW;
868     }
869    
870     const ParticlePointer TopPairEventCandidate::getLeptonicTop() const {
871     throwExpeptionIfNotReconstructed("TopPairEventCandidate::getLeptonicTop");
872     if (selectedNeutrino == 1)
873     return leptonicTop1;
874     else
875     return leptonicTop2;
876     }
877    
878     const ParticlePointer TopPairEventCandidate::getHadronicTop() const {
879     throwExpeptionIfNotReconstructed("TopPairEventCandidate::getHadronicTop");
880     return hadronicTop;
881     }
882    
883     const ParticlePointer TopPairEventCandidate::getResonance() const {
884     throwExpeptionIfNotReconstructed("TopPairEventCandidate::getResonance");
885     return ttbarResonance;
886     }
887    
888     double TopPairEventCandidate::M3() const {
889     double m3(0), max_pt(0);
890     if (goodJets.size() >= 3) {
891     for (unsigned int index1 = 0; index1 < goodJets.size() - 2; ++index1) {
892     for (unsigned int index2 = index1 + 1; index2 < goodJets.size() - 1; ++index2) {
893     for (unsigned int index3 = index2 + 1; index3 < goodJets.size(); ++index3) {
894     FourVector m3Vector(goodJets.at(index1)->getFourVector() + goodJets.at(index2)->getFourVector()
895     + goodJets.at(index3)->getFourVector());
896     double currentPt = m3Vector.Pt();
897     if (currentPt > max_pt) {
898     max_pt = currentPt;
899     m3 = m3Vector.M();
900     }
901     }
902     }
903     }
904     }
905    
906     return m3;
907     }
908    
909    
910     double TtbarHypothesis::M3() const {
911     double m3(0), max_et(0);
912     JetCollection mcJets;
913     mcJets.clear();
914     mcJets.push_back(jet1FromW);
915     mcJets.push_back(jet2FromW);
916     mcJets.push_back(leptonicBjet);
917     mcJets.push_back(hadronicBJet);
918     if (mcJets.size() >= 3) {
919     for (unsigned int index1 = 0; index1 < mcJets.size() - 2; ++index1) {
920     for (unsigned int index2 = index1 + 1; index2 < mcJets.size() - 1; ++index2) {
921     for (unsigned int index3 = index2 + 1; index3 < mcJets.size(); ++index3) {
922     FourVector m3Vector(mcJets.at(index1)->getFourVector() + mcJets.at(index2)->getFourVector()
923     + mcJets.at(index3)->getFourVector());
924     double currentEt = m3Vector.Et();
925     if (currentEt > max_et) {
926     max_et = currentEt;
927     m3 = m3Vector.M();
928     }
929     }
930     }
931     }
932     }
933    
934     return m3;
935     }
936    
937     double TopPairEventCandidate::mttbar() const {
938     return getResonance()->mass();
939     }
940    
941     const std::vector<TtbarHypothesisPointer>& TopPairEventCandidate::Solutions() const{
942     return solutions;
943     }
944    
945     void TopPairEventCandidate::inspectReconstructedEvent() const {
946     cout << "run " << runNumber << ", event " << eventNumber << endl;
947     cout << "leptonic b jet, goodJet index " << leptonicBIndex << endl;
948     EventContentPrinter::printJet(leptonicBJet);
949    
950     cout << "lepton from W" << endl;
951     // EventContentPrinter::printElectron(electronFromW);
952    
953     cout << "MET" << endl;
954     EventContentPrinter::printParticle(met);
955     cout << endl;
956    
957     cout << "reconstructed neutrino 1(selected: " << selectedNeutrino << ")" << endl;
958     EventContentPrinter::printParticle(neutrino1);
959     cout << endl;
960    
961     cout << "reconstructed neutrino 2(selected: " << selectedNeutrino << ")" << endl;
962     EventContentPrinter::printParticle(neutrino2);
963     cout << endl;
964    
965     cout << "leptonic W 1 (selected: " << selectedNeutrino << ")" << endl;
966     EventContentPrinter::printParticle(leptonicW1);
967     cout << endl;
968    
969     cout << "leptonic W 2 (selected: " << selectedNeutrino << ")" << endl;
970     EventContentPrinter::printParticle(leptonicW2);
971     cout << endl;
972    
973     cout << "leptonic top 1 (selected: " << selectedNeutrino << ")" << endl;
974     EventContentPrinter::printParticle(leptonicTop1);
975     cout << endl;
976    
977     cout << "leptonic top 2 (selected: " << selectedNeutrino << ")" << endl;
978     EventContentPrinter::printParticle(leptonicTop2);
979     cout << endl;
980    
981     cout << "hadronic b jet, goodJet index " << hadronicBIndex << endl;
982     EventContentPrinter::printJet(hadronicBJet);
983    
984     cout << "jet1 from W, goodJet index " << jet1FromWIndex << endl;
985     EventContentPrinter::printJet(jet1FromW);
986    
987     cout << "jet 2 from W, goodJet index " << jet2FromWIndex << endl;
988     EventContentPrinter::printJet(jet2FromW);
989    
990     cout << "hadronic W" << endl;
991     EventContentPrinter::printParticle(hadronicW);
992     cout << endl;
993    
994     cout << "hadronic top" << endl;
995     EventContentPrinter::printParticle(hadronicTop);
996     cout << endl;
997     }
998    
999     double TopPairEventCandidate::fullHT() const {
1000     double ht(met->pt());
1001    
1002     for (unsigned int index = 0; index < goodPFIsolatedElectrons.size(); ++index) {
1003     ht += goodPFIsolatedElectrons.at(index)->pt();
1004     }
1005    
1006     for (unsigned int index = 0; index < goodIsolatedMuons.size(); ++index) {
1007     ht += goodIsolatedMuons.at(index)->pt();
1008     }
1009    
1010     for (unsigned int index = 0; index < goodJets.size(); ++index) {
1011     ht += goodJets.at(index)->pt();
1012     }
1013     return ht;
1014     }
1015    
1016     double TopPairEventCandidate::transverseWmass(const LeptonPointer lepton) const {
1017     double energySquared = pow(lepton->et() + met->et(), 2);
1018     double momentumSquared = pow(lepton->px() + met->px(), 2) + pow(lepton->py() + met->py(), 2);
1019     double tMassSquared = energySquared - momentumSquared;
1020    
1021     if (tMassSquared > 0)
1022     return sqrt(tMassSquared);
1023     else
1024     return -1;
1025     }
1026    
1027     void TopPairEventCandidate::reconstruct(Rule rule, const LeptonPointer lepton) {
1028     //TODO: change this into if(!Rule::meetsInitialConditaion())
1029     if (goodJets.size() < 4 || lepton == 0)
1030     throw ReconstructionException("Not enough jets available to reconstruct top event using Mass Equality method.");
1031     leptonFromW = lepton;
1032     selectedNeutrino = 0;
1033     currentSelectedNeutrino = 0;
1034    
1035     reconstructNeutrinos();
1036     double chosen_TopMassDifference(9999999.);
1037     double chosen_Chi2Total(9999999.);
1038     for (unsigned short hadBindex = 0; hadBindex < goodJets.size(); ++hadBindex) {
1039     if (rule->hardHadronicBJetCondition(goodJets.at(hadBindex)))
1040     continue;
1041    
1042     for (unsigned short lepBindex = 0; lepBindex < goodJets.size(); ++lepBindex) {
1043     if (lepBindex == hadBindex || rule->hardLeptonicBJetCondition(goodJets.at(lepBindex)))
1044     continue;
1045    
1046     for (unsigned short jet1Index = 0; jet1Index < goodJets.size(); ++jet1Index) {
1047     if (jet1Index == lepBindex || jet1Index == hadBindex || rule->hardHadronicJetFromWCondition(
1048     goodJets.at(jet1Index)))
1049     continue;
1050    
1051     for (unsigned short jet2Index = 0; jet2Index < goodJets.size(); ++jet2Index) {
1052     if (jet2Index == jet1Index || jet2Index == lepBindex || jet2Index == hadBindex
1053     || rule->hardHadronicJetFromWCondition(goodJets.at(jet2Index)))
1054     continue;
1055    
1056     hadronicBJet = goodJets.at(hadBindex);
1057     leptonicBJet = goodJets.at(lepBindex);
1058     jet1FromW = goodJets.at(jet1Index);
1059     jet2FromW = goodJets.at(jet2Index);
1060    
1061     leptonicW1 = ParticlePointer(new Particle(*neutrino1 + *leptonFromW));
1062     leptonicW2 = ParticlePointer(new Particle(*neutrino2 + *leptonFromW));
1063     hadronicW = ParticlePointer(new Particle(*jet1FromW + *jet2FromW));
1064     leptonicTop1 = ParticlePointer(new Particle(*leptonicBJet + *leptonicW1));
1065     leptonicTop2 = ParticlePointer(new Particle(*leptonicBJet + *leptonicW2));
1066     hadronicTop = ParticlePointer(new Particle(*hadronicBJet + *hadronicW));
1067     fillHypotheses();
1068     selectNeutrinoSolution();
1069     double TopMassDifference = calculateTopMassDifference(currentSelectedNeutrino);
1070     double chi2 = getTotalChi2(currentSelectedNeutrino);
1071     switch (usedTTbarReconstruction) {
1072     case TTbarReconstructionCriterion::TopMassDifference:
1073     if (TopMassDifference < chosen_TopMassDifference) {
1074     hadronicBIndex = hadBindex;
1075     leptonicBIndex = lepBindex;
1076     jet1FromWIndex = jet1Index;
1077     jet2FromWIndex = jet2Index;
1078     chosen_TopMassDifference = TopMassDifference;
1079     selectedNeutrino = currentSelectedNeutrino;
1080     }
1081     break;
1082    
1083     case TTbarReconstructionCriterion::chi2:
1084     if (chi2 < chosen_Chi2Total) {
1085     hadronicBIndex = hadBindex;
1086     leptonicBIndex = lepBindex;
1087     jet1FromWIndex = jet1Index;
1088     jet2FromWIndex = jet2Index;
1089     chosen_Chi2Total = chi2;
1090     selectedNeutrino = currentSelectedNeutrino;
1091     }
1092     break;
1093     }
1094     }
1095     }
1096     }
1097     }
1098     compare_disc sorting;
1099     std::sort(solutions.begin(), solutions.end(), sorting);
1100     hadronicBJet = solutions.front()->hadronicBJet;
1101     leptonicBJet = solutions.front()->leptonicBjet;
1102     jet1FromW = solutions.front()->jet1FromW;
1103     jet2FromW = solutions.front()->jet2FromW;
1104     leptonicW1 = solutions.front()->leptonicW;
1105     leptonicW2 = solutions.front()->leptonicW;
1106     hadronicW = solutions.front()->hadronicW;
1107     // leptonicW1 = ParticlePointer(new Particle(*neutrino1 + *leptonFromW));
1108     // leptonicW2 = ParticlePointer(new Particle(*neutrino2 + *leptonFromW));
1109     // hadronicW = ParticlePointer(new Particle(*jet1FromW + *jet2FromW));
1110     leptonicTop1 = solutions.front()->leptonicTop;
1111     leptonicTop2 = solutions.front()->leptonicTop;
1112     hadronicTop = solutions.front()->hadronicTop;
1113     ttbarResonance = solutions.front()->resonance;
1114     if (selectedNeutrino == 1)
1115     ttbarResonance = ParticlePointer(new Particle(*leptonicTop1 + *hadronicTop));
1116     else
1117     ttbarResonance = ParticlePointer(new Particle(*leptonicTop2 + *hadronicTop));
1118     doneReconstruction = true;
1119     }
1120    
1121     }