ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/TPoll/src/RecoFirst.cc
Revision: 1.1
Committed: Mon Sep 19 15:48:29 2011 UTC (13 years, 7 months ago) by tonypoll
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Log Message:
Electron Timing

File Contents

# Content
1 // -*- C++ -*-
2 //
3 // Package: RecoFirst
4 // Class: RecoFirst
5 //
6 /**\class RecoFirst RecoFirst.cc recoFirst/RecoFirst/src/RecoFirst.cc
7
8 Description: Displaced vertex method for long lived reconstruction
9
10 Implementation:
11 From a MC sample find a RECO electron or photon
12 Find a matching MC lepton
13 See if MC lepton is a (grand+)daughter of signal (Z or Z', say)
14 Construct displaced vertex and hence reconstructed mass
15 Apply iterative algorithm to refine solution
16
17 This analysis works with both RECO and AOD data
18 The reconstructed particles are generically referred to as RECO
19 To distinguish reconstructed particles vs MC
20 */
21 //
22 // Original Author: Tony Poll
23 // Created: Thu Jul 7 12:48:08 BST 2011
24 // $Id$
25 //
26 //
27
28
29 // system include files
30 #include <memory>
31 #include <typeinfo>
32
33 // user include files
34
35 #include "FWCore/Framework/interface/Frameworkfwd.h"
36 #include "FWCore/Framework/interface/EDAnalyzer.h"
37 #include "FWCore/Framework/interface/Event.h"
38 #include "FWCore/Framework/interface/MakerMacros.h"
39 #include "FWCore/ParameterSet/interface/ParameterSet.h"
40 #include "DataFormats/Common/interface/Handle.h"
41 #include "DataFormats/VertexReco/interface/Vertex.h"
42 #include "DataFormats/VertexReco/interface/VertexFwd.h"
43 #include "DataFormats/HepMCCandidate/interface/GenParticle.h"
44
45 #include "DataFormats/EgammaCandidates/interface/Electron.h"
46 #include "DataFormats/EgammaCandidates/interface/GsfElectron.h"
47 #include "DataFormats/EgammaCandidates/interface/Photon.h"
48
49 #include "DataFormats/EgammaCandidates/interface/GsfElectronFwd.h"
50 #include "DataFormats/EgammaCandidates/interface/GsfElectronCore.h"
51 #include "DataFormats/RecoCandidate/interface/RecoCandidate.h"
52 #include "DataFormats/GsfTrackReco/interface/GsfTrackFwd.h"
53 #include "DataFormats/GsfTrackReco/interface/GsfTrack.h"
54 #include "DataFormats/TrackReco/interface/TrackFwd.h"
55 #include "DataFormats/EgammaReco/interface/SuperCluster.h"
56 #include "DataFormats/EgammaReco/interface/SuperClusterFwd.h"
57 #include "DataFormats/CaloRecHit/interface/CaloClusterFwd.h"
58 #include <DataFormats/CaloRecHit/interface/CaloCluster.h>
59 #include <DataFormats/EgammaReco/interface/BasicCluster.h>
60 //#include "DataFormats/Math/interface/LorentzVector.h"
61 #include "DataFormats/GeometryVector/interface/GlobalPoint.h"
62 #include "DataFormats/GeometryVector/interface/GlobalVector.h"
63 #include "FWCore/MessageLogger/interface/MessageLogger.h"
64 #include <DataFormats/Common/interface/Ref.h>
65 #include <DataFormats/DetId/interface/DetId.h>
66
67 #include "RecoEcal/EgammaCoreTools/interface/EcalClusterLazyTools.h"
68 #include "RecoEcal/EgammaCoreTools/interface/EcalClusterTools.h"
69 #include <DataFormats/EgammaReco/interface/BasicCluster.h>
70 #include <DataFormats/CaloRecHit/interface/CaloRecHit.h>
71
72 #include "FWCore/Framework/interface/Frameworkfwd.h"
73 #include "FWCore/Framework/interface/EDAnalyzer.h"
74 #include "FWCore/Framework/interface/Event.h"
75 #include "FWCore/Framework/interface/EventSetup.h"
76 #include "FWCore/Framework/interface/MakerMacros.h"
77 #include "FWCore/ParameterSet/interface/ParameterSet.h"
78 #include "FWCore/Framework/interface/ESHandle.h"
79 #include "FWCore/ServiceRegistry/interface/Service.h"
80 #include "CommonTools/UtilAlgos/interface/TFileService.h"
81 #include "Geometry/EcalMapping/interface/EcalMappingRcd.h"
82
83 #include "DataFormats/EcalDigi/interface/EcalDigiCollections.h"
84 #include "DataFormats/EcalRecHit/interface/EcalRecHit.h"
85 #include "DataFormats/EcalRecHit/interface/EcalRecHitCollections.h"
86 #include "DataFormats/DetId/interface/DetId.h"
87 #include "DataFormats/EcalRawData/interface/EcalRawDataCollections.h"
88 #include "DataFormats/EcalRawData/interface/EcalDCCHeaderBlock.h"
89 #include "DataFormats/Candidate/interface/LeafCandidate.h"
90 #include "DataFormats/Candidate/interface/Candidate.h"
91
92 #include "Geometry/EcalMapping/interface/EcalElectronicsMapping.h"
93 #include "Geometry/CaloTopology/interface/CaloTopology.h"
94 #include "Geometry/CaloEventSetup/interface/CaloTopologyRecord.h"
95
96 #include "CaloOnlineTools/EcalTools/interface/EcalFedMap.h"
97
98 #include "RecoCaloTools/Navigation/interface/CaloNavigator.h"
99 #include <CommonTools/Utils/interface/Angle.h>
100
101 #include "RecoFirst.h"
102 #include "TVector3.h"
103 #include "TFile.h"
104 #include "TTree.h"
105 #include "TText.h"
106 #include "TGraphAsymmErrors.h"
107
108 #include "CLHEP/Geometry/Transform3D.h"
109
110
111 //
112 // class declaration
113 //
114 /*
115 class RecoFirst : public edm::EDAnalyzer {
116 public:
117 explicit RecoFirst(const edm::ParameterSet&);
118 ~RecoFirst();
119
120 static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
121
122
123 private:
124 virtual void beginJob() ;
125 virtual void analyze(const edm::Event&, const edm::EventSetup&);
126 virtual void endJob() ;
127
128 virtual void beginRun(edm::Run const&, edm::EventSetup const&);
129 virtual void endRun(edm::Run const&, edm::EventSetup const&);
130 virtual void beginLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&);
131 virtual void endLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&);
132
133 // ----------member data ---------------------------
134 };
135 */
136
137 //
138 // constants, enums and typedefs
139 //
140 using namespace edm;
141 using namespace std;
142
143 edm::Handle<EcalRecHitCollection> EBhits_;
144 edm::Handle<EcalRecHitCollection> EEhits_;
145
146 edm::Handle<vector<reco::GsfElectron> > ElectronCollection;
147 edm::Handle<vector<reco::Photon> > PhotonCollection;
148
149 float speedOfLight_ = 30.0; // speed of light in units of cm/ns
150 float decayLengthAccuracy = 0.01; // difference between one iteration & the next when calculating decay length (%)
151 float timeAccuracy = 0.02; // Iterate until differences in measured and calculated flight time are less than this (ns)
152
153 const int pdgIdElectron = 11;
154 const int pdgIdMuon = 13;
155 const int pdgIdTau = 15;
156 const int pdgIdPhoton = 22;
157
158 // Number of each long lived daughter decay types
159 int numberOfElectrons = 0;
160 int numberOfPhotons = 0;
161 int numberOfElectronPhotonPairs = 0;
162 int numberOfDaughters = 0;
163 int lowCrystalHitEnergy = 0;
164 int negativeHitTime = 0;
165 int noDisplacedVertexConvergence = 0;
166 int ValidatedReconstructions = 0;
167 int nonPhysicalDecayLength = 0;
168 int closeElectronsWithNegativeHitTime = 0;
169 int negativeFlightLength = 0;
170
171 int numberOfPrimaryVertexEvents = 0;
172 int ValidatedEvents = 0;
173 int noParticles = 0;
174 int numberOfZParticles = 0;
175 int numberOfZeventsAboveMinimumMass =0;
176 int numberOfZeventsWithTwoMcDaughters = 0;
177 int numberMcDaughterElectronsNotFinalState = 0;
178 int foundDaughters = 0;
179 int zDecaysWithEnergeticDaughters = 0;
180 int badRecoDeltaRMatch = 0;
181 int goodRecoElectron = 0;
182 int goodRecoPhoton = 0;
183 int noRecoMatch = 0;
184 int nullSuperClusters = 0;
185 int zeroEnergyLepton = 0;
186 int zWithTwoRecoDaughters = 0;
187 int numberOfZsWithoutTwoPositiveTimes = 0;
188 int numberOfDisplacedVertices = 0;
189 int lookingForLeptons = 0;
190 int particleHits = 0;
191 int recoPairsGoingIntoVeto = 0;
192 int recoPairsPassedVeto = 0;
193 int failedIsolation = 0;
194 int failedBarrelEndcapGap =0;
195 int failedEtaCut = 0;
196 int failedMinEt = 0;
197 int massReconstructions = 0;
198 int middleReconstructedMass = 0;
199 int massCalcCounter = 0;
200 int countValidations = 0;
201
202 // Array for Error Plots
203 int ErrorsCount = 0;
204 const int n = 10000;
205 float bestMass [n];
206 float bestFlightLength [n];
207 float lowMass [n];
208 float lowFlightLength [n];
209 float highMass [n];
210 float highFlightLength [n];
211
212 // Values for measured - error, measured, and measured + error values,
213 int low = 0;
214 int medium = 1;
215 int high = 2;
216
217 int ElectronDecays = 0;
218 int bremElectrons = 0;
219 int MuonDecays = 0;
220 int TauDecays = 0;
221 int PhotonDecays = 0;
222 int minimumAngleBetweenElectronsRejects = 0;
223
224 float crystalMinEnergy = 4.0; // Below 4 Gev hit time has too much error
225 // float crystalMinEnergy = 0.0; // Below 4 Gev hit time has too much error
226 float photonMinPt = 60.0; // Trigger, as of ~ 18/05/2011, rejects diphotons with Pt < 60GeV
227 // float minimumZMass = 30.0; // Don't consider off-shell MC Z events
228 float minimumZMass = 0.0; // Don't consider Pythia MC (gamma* + Z) 'particles'
229 // float minimumZMass = 80.0; // Don't consider Pythia MC (gamma* + Z) 'particles'
230 // float minimumAngleBetweenElectrons = 0.05; // Very small angles between electrons gives reconstructed mass ~ zero
231 float minimumAngleBetweenElectrons = 0.1; // Very small angles between electrons gives reconstructed mass ~ zero
232 float bremFraction = 0.2; // A high bremFraction means ECAL hit energy << parent energy, which results in poor mass reconstruction
233
234 float deltaConstructedMass = 0.10; // Iterate until changes are small
235 // float deltaConstructedMass = 0.01; // Iterate until changes are small
236
237 float dummy = -10;
238
239 // Photon selection cuts
240 float minimumMatchDeltaR = 0.1; // Reject MC to reco match if difference is greater than this value
241 // float maxEta = 50.0; // Photon eta cut
242 float maxEta = 2.5; // Photon eta cut
243 float isolationMinimum = 0.0; // isolation: deltaR between two photons
244 // float isolationMinimum = 0.45; // isolation: deltaR between two photons
245 // float photonMinEt = 1.0; // Electron/Photon cut
246 float photonMinEt = 30.0; // Electron/Photon cut
247 // float minDeltaR = 1.0; // MC to Reco electron deltaR
248 float minDeltaR = 0.5; // MC to Reco electron deltaR
249 float minDeltaOmega = 0.01; // Loop displaced vertex calc until change in angle betweeen electrons is small
250
251 float barrelLimit = 1.44;
252 float endcapLimit = 1.57;
253
254 float barrelTimingError = 0.27; //ns from CMS Note 2010/012
255 float endcapTimingError = 0.18;
256
257 math::XYZPoint PrimaryVertex_;
258 float AngleBetweenHits;
259
260 float pi = acos (-1);
261
262 // For histograms
263 map<string, TH1*> hists_;
264 map<string, TH2*> hists2d_;
265 map<string, TGraphAsymmErrors*> TGraphAsymmErrors_;
266
267 //bool minimum = true;
268 bool minimum = false;
269 bool measured = true;
270 // bool measured = false;
271 // bool maximum = true;
272 bool maximum = false;
273
274 // bool Z-ee = true;
275 bool Zee = false;
276 // bool ZPrimeee = true;
277 bool ZPrimeee = false;
278 bool LLee = true;
279 // bool LLee = false;
280
281 bool Debug1 = true;
282 // bool Debug1 = false;
283 // bool Debug2 = true;
284 bool Debug2 = false;
285
286 //
287 // static data member definitions
288 //
289
290 //
291 // constructors and destructor
292 //
293 RecoFirst::RecoFirst(const edm::ParameterSet& iConfig):
294 //now do what ever initialization is needed
295 PhotonSrc_ (iConfig.getParameter<InputTag>("Photons")),
296 electronSrc_ (iConfig.getParameter<InputTag>("gsfElectrons")),
297 EBRecHitCollection_ (iConfig.getParameter<InputTag>("EcalRecHitCollectionEB")),
298 EERecHitCollection_ (iConfig.getParameter<InputTag>("EcalRecHitCollectionEE")),
299 generatorTag_ (iConfig.getParameter<InputTag>("generatorSrc")),
300 signalPDGId_ (iConfig.getParameter<int>("signalPDGId"))
301 {
302 }
303
304
305 RecoFirst::~RecoFirst()
306 {
307
308 // do anything here that needs to be done at desctruction time
309 // (e.g. close files, deallocate resources etc.)
310
311 }
312
313
314 //
315 // member functions
316 //
317
318 // ------------ method called for each event ------------
319 void
320 RecoFirst::analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup)
321 {
322 using namespace edm;
323
324 if(Debug2){cout << "Starting to read event" << endl;}
325
326 // Get Ecal hits for this event
327 iEvent.getByLabel(EBRecHitCollection_, EBhits_);
328 if (EBhits_.failedToGet())
329 {
330 std::cout << "WARNING: cannot access EBhits_" << std::endl;
331 return;
332 }
333
334 iEvent.getByLabel(EERecHitCollection_, EEhits_);
335 if (EEhits_.failedToGet())
336 {
337 std::cout << "WARNING: cannot access EEhits_" << std::endl;
338 return;
339 }
340 if(Debug2){cout << "EBhits: " << EBhits_->size() << ", EEhits: " << EEhits_->size() << endl;}
341
342 // Get electron collection
343 iEvent.getByLabel(electronSrc_, ElectronCollection); // Indirectly pointed to in recofirst_cfi.py
344 if (ElectronCollection.failedToGet())
345 {
346 std::cout << "WARNING: cannot access ElectronCollection" << std::endl;
347 return;
348 }
349 if(Debug2) {cout << "Number of electrons: " << ElectronCollection->size() << endl;}
350 // Get photon collection
351 iEvent.getByLabel(PhotonSrc_, PhotonCollection); // Indirectly pointed to in recofirst_cfi.py
352 if (PhotonCollection.failedToGet())
353 {
354 std::cout << "WARNING: cannot access PhotonCollection" << std::endl;
355 return;
356 }
357 if(Debug2) {cout << "Number of photons: " << PhotonCollection->size() << endl;}
358
359 // Get primary vertex
360 getPrimaryVertex(iEvent);
361
362 // Confirm algorithms accurately reconstructed parent flight length and mass
363 // *************************************************************************
364 // By comparing RECO particle reconstructions (mass & flight length) to 'true' MC particle values
365 // If the two RECO electrons are close to the MC electrons (i.e. deltaR is small)
366 // Plot (reconstructed mass vs true MC mass) and (reconstructed flight length vs true MC flight length)
367
368 std::vector<reco::GenParticle> goodMcElectrons;
369
370 // Create a particle, with initial dummy values, to hold the Monte Calro signal
371 myParticle McSignal (dummy);
372
373 // Get MC particles
374 edm::Handle<View<reco::GenParticle> > Particles;
375 iEvent.getByLabel(generatorTag_, Particles); // 'generatorTag_' defined in recofirst_cfi.py
376 if (Particles.failedToGet())
377 {
378 noParticles++;
379 if (Debug2) {cout << "No MC particles in this event" << endl; }
380 // return; // Do not exit as real physics data will not have MC particles
381 }
382 else // Only do this if the sample contains MC particles
383 {
384 // Match RECO electrons/photons to MC electrons that are descendants of our signal (Z, Z' or LL)
385 // Rather than attempt to match to all the MC particles every time, which would be slow,
386 // create a collection of MC electrons that are descendants of our signal
387 bool signalFound = false;
388 for (unsigned imc = 0; imc < Particles->size(); ++imc) // Get the MC particles
389 {
390 // Looking for MC electron/positron in final state i.e. Pythia status == 1
391 if((abs((*Particles)[imc].pdgId()) == pdgIdElectron) && ((*Particles)[imc].status()==1))
392 {
393 if(Debug2){cout << "Got a MC final state electron" << endl;}
394 reco::GenParticle decayParticle;
395 decayParticle = (*Particles)[imc];
396 // Now navigate up the decay chain looking for our signal particle
397 for (unsigned i = 0; i < decayParticle.numberOfMothers(); ++i)
398 {
399 const reco::Candidate* mother = decayParticle.mother(i);
400 // 'signalPDGId_' defined in recofirst_cfi.py
401 while ((mother->pdgId() != signalPDGId_) && (mother->numberOfMothers() != 0 ))
402 {
403 mother = mother->mother(0);
404 }
405 // if ((mother->pdgId() == signalPDGId_) && (mother->status() == 3))
406 if ((mother->pdgId() == signalPDGId_))
407 {
408 signalFound = true;
409 goodMcElectrons.push_back(decayParticle); // Store good MC electrons
410 McSignal.mass[medium] = mother->p4().M();
411 McSignal.energy = mother->energy();
412 if(Debug2){cout << "Signal mass: " << McSignal.mass[medium] << endl;}
413 McSignal.flightLength[medium] = getFlightLength(mother);
414 // Plot MC mass & flight length
415 hists_["t6"]->Fill(McSignal.mass[medium]); // True (MC) mass
416 hists_["t3"]->Fill(McSignal.flightLength[medium]); // True (MC) flight length
417 }
418 else if(Debug2) {cout << "Got a bad signal MC mother: " << i << " with PDGId: " << mother->pdgId() << endl;}
419 }
420 }
421 }
422 }
423
424 // Create an instance for the two daughter particles and the reconstructed particle
425 // Initialised with dummy values: usually -10, as this is easily spotted when not set with calculated values
426 myParticle firstDaughterRECO (dummy);
427 myParticle secondDaughterRECO (dummy);
428 myParticle reconstructedRECOParent(dummy);
429
430 // Get some statistics: number of electrons, photons, those without a supercluster, low ECAL crystal energy, negative ECAL hit time etc
431 if(Debug2){cout << "Number of electrons: " << ElectronCollection->size() << endl;}
432 if(Debug2){cout << "Number of photons: " << PhotonCollection->size() << endl;}
433 for(std::vector<reco::GsfElectron>::const_iterator firstElectron = ElectronCollection->begin(); firstElectron != ElectronCollection->end(); ++firstElectron)
434 {
435 getDaughterStats(firstDaughterRECO, firstElectron);
436 }
437 for(std::vector<reco::Photon>::const_iterator firstPhoton = PhotonCollection->begin(); firstPhoton != PhotonCollection->end(); ++firstPhoton)
438 {
439 getDaughterStats(firstDaughterRECO, firstPhoton);
440 }
441
442 // Search for resonances
443 // Find all electron/photon pairs and reconstruct an invariant mass
444 // Find the firstDaughterRECO electron
445 for(std::vector<reco::GsfElectron>::const_iterator firstElectron = ElectronCollection->begin(); firstElectron != ElectronCollection->end(); ++firstElectron)
446 {
447 numberOfElectrons++;
448 getDaughterParameters(firstDaughterRECO, firstElectron);
449 if(Debug2){cout << "Electron firstDaughterRECO.measuredHitTime: " << firstDaughterRECO.measuredHitTime[medium] << endl;}
450 // For an electron/electron pair find a second electron
451 for(std::vector<reco::GsfElectron>::const_iterator secondElectron = firstElectron + 1; secondElectron != ElectronCollection->end(); ++secondElectron)
452 {
453 numberOfElectronPhotonPairs++;
454 getDaughterParameters(secondDaughterRECO, secondElectron);
455 if(Debug2){cout << "Electron secondDaughterRECO.measuredHitTime: " << secondDaughterRECO.measuredHitTime[medium] << endl;}
456 reconstructMass(reconstructedRECOParent, firstDaughterRECO, secondDaughterRECO);
457 validate(McSignal, goodMcElectrons, reconstructedRECOParent, firstDaughterRECO, secondDaughterRECO);
458 }
459 // For an electron/photon pair find a photon
460 for(std::vector<reco::Photon>::const_iterator secondPhoton = PhotonCollection->begin(); secondPhoton != PhotonCollection->end(); ++secondPhoton)
461 {
462 numberOfElectronPhotonPairs++;
463 getDaughterParameters(secondDaughterRECO, secondPhoton);
464 if(Debug2){cout << "Photon secondDaughterRECO.measuredHitTime: " << secondDaughterRECO.measuredHitTime[medium] << endl;}
465 reconstructMass(reconstructedRECOParent, firstDaughterRECO, secondDaughterRECO);
466 validate(McSignal, goodMcElectrons, reconstructedRECOParent, firstDaughterRECO, secondDaughterRECO);
467 }
468 }
469
470 // Find photon/photon pairs
471 // Find the firstDaughterRECO photon
472 for(std::vector<reco::Photon>::const_iterator firstPhoton = PhotonCollection->begin(); firstPhoton != PhotonCollection->end(); ++firstPhoton)
473 {
474 numberOfPhotons++;
475 getDaughterParameters(firstDaughterRECO, firstPhoton);
476 if(Debug2){cout << "Photon firstDaughterRECO.measuredHitTime: " << firstDaughterRECO.measuredHitTime[medium] << endl;}
477 // For a photon/photon pair find the secondDaughterRECO photon
478 for(std::vector<reco::Photon>::const_iterator secondPhoton = firstPhoton + 1; secondPhoton != PhotonCollection->end(); ++secondPhoton)
479 {
480 numberOfElectronPhotonPairs++;
481 getDaughterParameters(secondDaughterRECO, secondPhoton);
482 if(Debug2){cout << "Photon secondDaughterRECO.measuredHitTime: " << secondDaughterRECO.measuredHitTime[medium] << endl;}
483 reconstructMass(reconstructedRECOParent, firstDaughterRECO, secondDaughterRECO);
484 validate(McSignal, goodMcElectrons, reconstructedRECOParent, firstDaughterRECO, secondDaughterRECO);
485 }
486 }
487 }
488
489
490 // Compare calculated values against true MC flight length and mass
491 // Check both daughters come from the same parent (In LL samples there will be two LL decays)
492 // Check each daughter is close (i.e. small deltaR) to MC electron or photon
493 void
494 RecoFirst::validate(myParticle McSignal, std::vector<reco::GenParticle> McElectrons, myParticle reconstructedRECOParent, myParticle firstDaughterRECO, myParticle secondDaughterRECO)
495 {
496 countValidations++;
497
498 if(reconstructedRECOParent.mass[medium] != dummy) // If mass is not reconstructed it retains its initialisation negative value
499 {
500
501 // If MC electrons are close (small deltaR) to RECO electrons, then
502 // plot MC vs reconstructedRECOParent mass
503 // plot MC flight length vs reconstructedRECOParent flight length
504 if(Debug2){cout << "McSignalMass: " << McSignal.mass[medium] << endl;}
505 // Note: An electron that decays from the signal may decay into a subsequent electron, while emitting brem radiation.
506 // Therefore the best match electron may or may not be either the initial or final electron in the decay chain
507 for (std::vector<reco::GenParticle>::const_iterator McElectron1 = McElectrons.begin(); McElectron1 != McElectrons.end(); McElectron1++)
508 {
509 float parentPt1 = parentPt(McElectron1->mother()); // Navigate up the decay chain until the signal is found, then get its Pt
510 if (parentPt1 == dummy) continue; // Only proceed if we have a real Pt
511 for (std::vector<reco::GenParticle>::const_iterator McElectron2 = McElectron1 + 1; McElectron2 != McElectrons.end(); McElectron2++)
512 {
513 // Only proceed is McElectron2 is not a daughter of McElectron1, or McElectron1 is not a daughter of McElectron2
514 // We want two electrons from separate electron decay chains (this is different from two electrons from the same signal parent).
515 // Note: You must dereference the McElectron as it is a pointing into a vector (which itself is an array of pointers)
516 if (sameDecayChain(*McElectron1, *McElectron2)) continue;
517 // Only proceed if the two MC particles share the same parent, as confirmed by its pt
518 // if (Debug1){cout << "typeid(McElectron1).name(): " << typeid(McElectron1).name() << endl;}
519 if (parentPt1 != parentPt(McElectron2->mother())) continue; // Same parent?
520
521 if (Debug2) {cout << "Got two MC electrons with the same signal parent" << endl;}
522 // Is the first RECO daughter close to one MC electron
523 // and the second RECO daughter close to the other MC electron?
524 // float deltaRValue = deltaR(McElectron1, firstDaughterRECO);
525 float deltaPhi1 = calcDeltaPhi(McElectron1->phi(), firstDaughterRECO.phi);
526 float deltaEta1 = calcDeltaEta(McElectron1->eta(), firstDaughterRECO.eta);
527 float deltaPhi2 = calcDeltaPhi(McElectron2->phi(), secondDaughterRECO.phi);
528 float deltaEta2 = calcDeltaEta(McElectron2->eta(), secondDaughterRECO.eta);
529
530 float deltaPhi3 = calcDeltaPhi(McElectron2->phi(), firstDaughterRECO.phi);
531 float deltaEta3 = calcDeltaEta(McElectron2->eta(), firstDaughterRECO.eta);
532 float deltaPhi4 = calcDeltaPhi(McElectron1->phi(), secondDaughterRECO.phi);
533 float deltaEta4 = calcDeltaEta(McElectron1->eta(), secondDaughterRECO.eta);
534
535 // Only proceed if both RECO electrons are close to different MC electrons
536 if ( !( ( // firstDaughterRECO close to McElectron1 ?
537 (sqrt ((deltaPhi1 * deltaPhi1) + (deltaEta1 * deltaEta1)) < minDeltaR) &&
538 // secondDaughterRECO close to McElectron2 ?
539 (sqrt ((deltaPhi2 * deltaPhi2) + (deltaEta2 * deltaEta2)) < minDeltaR) )
540 || // OR
541 ( // firstDaughterRECO close to McElectron2 ?
542 (sqrt ((deltaPhi3 * deltaPhi3) + (deltaEta3 * deltaEta3)) < minDeltaR) &&
543 // second DaughterRECO close to McElectron1 ?
544 (sqrt ((deltaPhi4 * deltaPhi4) + (deltaEta4 * deltaEta4)) < minDeltaR) )
545 )) continue; // Skip loop if the two RECO electrons don't match separate MC electrons
546 {
547 ValidatedReconstructions++;
548 if ((firstDaughterRECO.measuredHitTime[medium] != dummy) && // Only plot measured hit times
549 (secondDaughterRECO.measuredHitTime[medium] != dummy))
550 {
551 closeElectronsWithNegativeHitTime++;
552 }
553 if (reconstructedRECOParent.flightLength[medium] < 0.0)
554 {
555 negativeFlightLength++;
556 }
557
558 // Find (true) angle between the two MC electrons
559 reco::GenParticle::Vector McParticleMom1 = McElectron1->momentum();
560 reco::GenParticle::Vector McParticleMom2 = McElectron2->momentum();
561 double McIncludedAngle = acos(McParticleMom1.Dot(McParticleMom2)/McParticleMom1.R()/McParticleMom2.R());
562 if (Debug2) {cout << "McIncludedAngle: " << McIncludedAngle << endl;}
563
564 // Calculate the expected MC hit time. I.e. LL flight time + electron flight time
565 float McSignalGamma = McSignal.energy / McSignal.mass[medium];
566 float McSignalVelocity = speedOfLight_ * sqrt( 1 - 1/(McSignalGamma * McSignalGamma));
567 if (Debug1){cout << "McSignalVelocity: " << McSignalVelocity << endl;}
568 float McSignalFlightTime = McSignal.flightLength[medium] / McSignalVelocity;
569 if (Debug1){cout << "McSignalFlightTime: " << McSignalFlightTime << endl;}
570 float McElectronFlightTime1 = sqrt( (McParticleMom1.X() * McParticleMom1.X()) + (McParticleMom1.Y() * McParticleMom1.Y()) + (McParticleMom1.Z() * McParticleMom1.Z()) )/speedOfLight_;
571 float McElectronFlightTime2 = sqrt( (McParticleMom2.X() * McParticleMom2.X()) + (McParticleMom2.Y() * McParticleMom2.Y()) + (McParticleMom2.Z() * McParticleMom2.Z()) )/speedOfLight_;
572 McSignal.calculatedHitTime[1] = McSignalFlightTime + McElectronFlightTime1; // MC LL flight time + MC electron1 flight time
573 McSignal.calculatedHitTime[2] = McSignalFlightTime + McElectronFlightTime2; // MC LL flight time + MC electron2 flight time
574
575 hists_["t35"]->Fill(McSignalFlightTime);
576 hists_["t36"]->Fill(McElectronFlightTime1);
577 hists_["t36"]->Fill(McElectronFlightTime2);
578
579 // We need the time relative to a photon travelling at velocity from the primary vertex
580 // Find the XYZ coords of the hit for each electron
581 float x1 = McElectron1->vx() + McElectron1->px();
582 float y1 = McElectron1->vy() + McElectron1->py();
583 float z1 = McElectron1->vz() + McElectron1->pz();
584 float x2 = McElectron2->vx() + McElectron2->px();
585 float y2 = McElectron2->vy() + McElectron2->py();
586 float z2 = McElectron2->vz() + McElectron2->pz();
587
588 // Time for a photon to travel from IP to hit position
589 float time1 = (sqrt(x1*x1 + y1*y1 + z1*z1))/speedOfLight_;
590 float time2 = (sqrt(x2*x2 + y2*y2 + z2*z2))/speedOfLight_;
591 hists_["t37"]->Fill(time1);
592 hists_["t37"]->Fill(time2);
593
594 // Plot the MC vs measured times (relative to time=0 for a relativistic particle)
595 // Want to plot hit times for correct MC & RECO electron pairs
596 // firstDaughterRECO close to McElectron1 ?
597 if (sqrt ((deltaPhi1 * deltaPhi1) + (deltaEta1 * deltaEta1)) < minDeltaR)
598 {
599 if (Debug1){cout << "First pair match" << endl;}
600 hists_["t33"]->Fill(McSignal.calculatedHitTime[1] - time1, firstDaughterRECO.measuredHitTime[medium]);
601 hists_["t33"]->Fill(McSignal.calculatedHitTime[2] - time2, secondDaughterRECO.measuredHitTime[medium]);
602 }
603 else
604 {
605 if (Debug1){cout << "Second pair match" << endl;}
606 hists_["t33"]->Fill(McSignal.calculatedHitTime[2] - time2, firstDaughterRECO.measuredHitTime[medium]);
607 hists_["t33"]->Fill(McSignal.calculatedHitTime[1] - time1, secondDaughterRECO.measuredHitTime[medium]);
608 }
609
610 // Plot actual hit time i.e. don't subtract time for photon to travel from IP to ECAL hit
611 float x = firstDaughterRECO.endPoint.x();
612 float y = firstDaughterRECO.endPoint.y();
613 float z = firstDaughterRECO.endPoint.z();
614 float timeAdjustment = sqrt(x*x + y*y + z*z)/speedOfLight_;
615 firstDaughterRECO.calculatedHitTime[medium] = firstDaughterRECO.measuredHitTime[medium] + timeAdjustment;
616
617 x = secondDaughterRECO.endPoint.x();
618 y = secondDaughterRECO.endPoint.y();
619 z = secondDaughterRECO.endPoint.z();
620 timeAdjustment = sqrt(x*x + y*y + z*z)/speedOfLight_;
621 secondDaughterRECO.calculatedHitTime[medium] = secondDaughterRECO.measuredHitTime[medium] + timeAdjustment;
622
623 // Plot the MC vs measured absolute times (No adjustment for time=0 for a relativistic particle)
624 // Want to plot hit times for correct MC & RECO electron pairs
625 // firstDaughterRECO close to McElectron1 ?
626 if (sqrt ((deltaPhi1 * deltaPhi1) + (deltaEta1 * deltaEta1)) < minDeltaR)
627 {
628 if (Debug1){cout << "First pair match" << endl;}
629 hists_["t34"]->Fill(McSignal.calculatedHitTime[1], firstDaughterRECO.calculatedHitTime[medium]);
630 hists_["t34"]->Fill(McSignal.calculatedHitTime[2], secondDaughterRECO.calculatedHitTime[medium]);
631 }
632 else
633 {
634 if (Debug1){cout << "Second pair match" << endl;}
635 hists_["t34"]->Fill(McSignal.calculatedHitTime[2], firstDaughterRECO.calculatedHitTime[medium]);
636 hists_["t34"]->Fill(McSignal.calculatedHitTime[1], secondDaughterRECO.calculatedHitTime[medium]);
637 }
638
639
640 if (Debug2) {cout << "McSignal flight Length: " << McSignal.flightLength[medium] << endl;}
641
642 //If both RECO electrons are close to MC electrons, then compare true vs reconstructed mass & flight length
643 if ((reconstructedRECOParent.flightLength[medium] >= 0.0) // flight length < 0 is non-physical
644 && (firstDaughterRECO.measuredHitTime[medium] != dummy) // Only plot measured hit times
645 && (secondDaughterRECO.measuredHitTime[medium] != dummy)
646 && (reconstructedRECOParent.omega[medium] > minimumAngleBetweenElectrons ) // Large errors if angle between electrons is small
647 && ((McSignal.energy - (firstDaughterRECO.energy + secondDaughterRECO.energy))/McSignal.energy < (bremFraction) ) // Reject events with high brem
648 )
649 {
650 hists_["t4"]->Fill(McSignal.flightLength[medium], reconstructedRECOParent.flightLength[medium]); // True (MC) mass vs constructed flight length
651 hists_["t12"]->Fill(McSignal.mass[medium], reconstructedRECOParent.mass[medium]); // True (MC) mass vs constructed mass
652 hists_["t13"]->Fill(reconstructedRECOParent.flightLength[medium] - McSignal.flightLength[medium], reconstructedRECOParent.mass[medium] - McSignal.mass[medium]); // Reconstructed flight length residual vs Reconstructed mass residual
653 hists_["t14"]->Fill(reconstructedRECOParent.flightLength[medium]); // Reconstructed flight length for 'good' electron pairs
654
655 // if (firstDaughterRECO.measuredHitTime[medium] != dummy) // Only plot measured hit times
656 {
657 hists_["t15"]->Fill(firstDaughterRECO.measuredHitTime[medium]); // ECAL hit time for 'good' electron
658 }
659 // if (secondDaughterRECO.measuredHitTime[medium] != dummy) // Only plot measured hit times
660 {
661 hists_["t15"]->Fill(secondDaughterRECO.measuredHitTime[medium]); // ECAL hit time for 'good' electron
662 }
663 hists_["t16"]->Fill(McSignal.mass[medium], reconstructedRECOParent.mass[medium] - McSignal.mass[medium]); // Reconstructed flight length residual vs Reconstructed mass residual
664 hists_["t17"]->Fill(reconstructedRECOParent.mass[medium]); // Reconstructed mass for electron hits matched to two MC electrons with same signal parent
665 hists_["t18"]->Fill(reconstructedRECOParent.flightLength[medium]); // Reconstructed flight length for electron hits matched to two MC electrons with same signal parent
666 hists_["t19"]->Fill(McSignal.flightLength[medium], reconstructedRECOParent.flightLength[medium]); // MC vs Reconstructed flight length for electron hits matched to two MC electrons with same signal parent
667 hists_["t23"]->Fill(reconstructedRECOParent.flightLength[medium], reconstructedRECOParent.omega[medium]); // How included angle depends upon flight length
668 hists_["t24"]->Fill(McSignal.flightLength[medium], reconstructedRECOParent.flightLength[medium] - McSignal.flightLength[medium]); // How constructed flight length error depends upon MC flight length
669 hists_["t25"]->Fill(reconstructedRECOParent.omega[medium], reconstructedRECOParent.mass[medium]); // How reconstructed mass depends upon included angle
670 hists_["t26"]->Fill(sqrt(firstDaughterRECO.energy * secondDaughterRECO.energy), reconstructedRECOParent.mass[medium]); // How reconstructed mass depends upon energy of daughters
671 hists_["t27"]->Fill((firstDaughterRECO.energy * secondDaughterRECO.energy), (1-cos(reconstructedRECOParent.omega[medium]))); // How constructed included angle depends upon energy of daughters
672 hists_["t28"]->Fill(McIncludedAngle, McSignal.mass[medium]); // MC (true) included angle vs MC (true) mass
673 hists_["t29"]->Fill(McIncludedAngle, reconstructedRECOParent.omega[medium]); // MC (true) included angle vs reconstructed included angle
674 hists_["t30"]->Fill(McSignal.flightLength[medium], McIncludedAngle); // MC (true) flight length vs MC (true) included angle
675 hists_["t31"]->Fill(McIncludedAngle); // MC (true) included angle
676 hists_["t32"]->Fill(reconstructedRECOParent.omega[medium]); // Constructed included angle
677
678 if (Debug2)
679 {
680 // If true mass >> reconstructed mass - to highlight serious mis-constructions
681 if (McSignal.mass[medium]/reconstructedRECOParent.mass[medium] > 1.4)
682 {
683 cout << "Reconstructed MC mass ratio: " << McSignal.mass[medium]/reconstructedRECOParent.mass[medium] << endl;
684 cout << "MC signal parent mass : " << McSignal.mass[medium] << endl;
685 cout << "Reconstructed MC mass: " << reconstructedRECOParent.mass[medium] << endl;
686 }
687 }
688 }
689 return;
690 }
691 }
692 }
693 }
694 }
695
696
697 // Return the Pt of a McParticle's parent
698 float
699 RecoFirst::parentPt(const reco::Candidate* McParticle)
700 {
701 float McParticlePt = dummy;
702 while ((McParticle->pdgId() != signalPDGId_) && (McParticle->numberOfMothers() != 0))
703 {
704 McParticle = McParticle->mother(0);
705 }
706 if (McParticle->pdgId() == signalPDGId_)
707 {
708 McParticlePt = McParticle->pt();
709 }
710 if (Debug2){cout << "McParticle->pt: " << McParticlePt << endl;}
711 return McParticlePt;
712 }
713
714 // True if the electrons are from separate decay chains
715 // Compare electrons on their Pt.
716 bool
717 RecoFirst::sameDecayChain(const reco::GenParticle& McElectron1, const reco::GenParticle& McElectron2)
718 {
719 if (McElectron1.pt() == McElectron2.pt()) return true;
720
721 const reco::GenParticle& startMcElectron1 = McElectron1;
722 const reco::GenParticle& startMcElectron2 = McElectron2;
723
724 while ((McElectron1.pdgId() != signalPDGId_) && (McElectron1.numberOfMothers() != 0))
725 {
726 McElectron1 = McElectron1.mother(0);
727 if (McElectron1.pt() == startMcElectron2.pt()) return true;
728
729 }
730
731 while ((McElectron2.pdgId() != signalPDGId_) && (McElectron2.numberOfMothers() != 0))
732 {
733 McElectron2 = McElectron2.mother(0);
734 if (McElectron2.pt() == startMcElectron1.pt()) return true;
735 }
736 }
737
738 return false;
739 }
740
741
742
743 // Primary Vertex setup
744 void
745 RecoFirst::getPrimaryVertex(const edm::Event& iEvent)
746 {
747 // Get primary vertex
748 edm::Handle<reco::VertexCollection> primaryVertex;
749 iEvent.getByLabel("offlinePrimaryVertices", primaryVertex);
750 if(primaryVertex.failedToGet())
751 {
752 std::cout << "WARNING: cannot access PhotonCollection" << std::endl;
753 return;
754 }
755
756 numberOfPrimaryVertexEvents++;
757 if(Debug2) {cout << "Number of primary vertice(s): " << primaryVertex->size() << endl;}
758 // If more than one primary use the first
759 // TODO check which primary vertex should be used. Currently using the first which may be (?) the primary vertex with highest Pt
760 reco::Vertex pv = primaryVertex->front();
761 PrimaryVertex_ = pv.position();
762 }
763
764 float
765 RecoFirst::getFlightLength(const reco::Candidate* mother)
766 {
767 float flightLength = dummy; // A negative value that can be used for debugging, if required.
768 float dx=100000,dy=100000,dz=100000;
769 // We have the mother,
770 dx=mother->vertex().X();
771 dy=mother->vertex().Y();
772 dz=mother->vertex().Z();
773 if(Debug2){cout << "mother dx: " << dx << ", dy: " << dy << ", dz: " << dz << endl;}
774
775 // Calculate the x, y & z distances between the mother & daughter vertices
776 // If ( (particle is Pythia status == 3, or (not an electron or photon) ), and has a daughter: then get the daughter
777 while ( ( (mother->status() == 3 ) || !( (abs(mother->pdgId()) == pdgIdElectron) || (mother->pdgId() == pdgIdPhoton) ) )
778 && (mother->numberOfDaughters() != 0) )
779 {
780 mother = mother->daughter(0);
781 }
782 dx-=mother->vertex().X();
783 dy-=mother->vertex().Y();
784 dz-=mother->vertex().Z();
785 if(Debug2){cout << "mother - daughter dx: " << dx << ", dy: " << dy << ", dz: " << dz << endl;}
786 flightLength = sqrt(dx*dx + dy*dy + dz*dz);
787 if(Debug2){cout << "MC flight length: " << flightLength << endl;}
788 return flightLength;
789 }
790
791 // Reconstruct the long lived particle's invariant mass from the 2 daughter particles
792 // This is an iterative algorithm
793 // Find an initial displaced vertex, and hence an initial value for LL mass assuming the LL particle's velocity = speed of light
794 // Using the LL mass and energy, calculate its gamma value, and hence velocity
795 // With the new LL velocity and the displaced vertex calculate the time of flight of the LL.
796 // With the electron path length and velocity c calculate the time of flight of the lectron.
797 // Compare the LL plus electron flight times with the measured ECAL hit time
798 // Now iterate on LL flight length (displaced vertex) and direction until the calculated hit time is close to that measured
799 // Each time the displaced vertex changes the electron path also changes to retain the same hit position on the ECAL
800 void
801 RecoFirst::reconstructMass(myParticle &Parent, myParticle &firstDaughterRECO, myParticle &secondDaughterRECO) // pass particles 'by reference' so parameters are updated
802 {
803 if ((firstDaughterRECO.measuredHitTime[medium] == dummy) || (secondDaughterRECO.measuredHitTime[medium] == dummy))
804 {
805 if(Debug2){cout << "One or both electrons do not have a good ECAL hit time" << endl;}
806 return; // Exit if either hit time has not been set
807 }
808 Parent.flightLength[medium] = dummy; // Re-set values each time, else it retains previous values
809 Parent.mass[medium] = dummy;
810 // Only reconstruct mass for particles above the minimum Et
811 if ((firstDaughterRECO.et < photonMinEt) || (secondDaughterRECO.et < photonMinEt) )
812 {
813 if(Debug2){cout << "Low daughter Et" << endl;}
814 return; // Exit
815 }
816
817 massReconstructions++;
818 if(Debug2){cout << "Reconstructing mass" << endl;}
819 // Find the displaced vertex for the two particles
820
821 // Cannot find a displaced vertex if the timed flight length for (LL + daughter) < daughter direct flight length for either daughter
822 if((firstDaughterRECO.timedDistanceToHit[medium] < firstDaughterRECO.PrimaryVertexToHit) || (secondDaughterRECO.timedDistanceToHit[medium] < secondDaughterRECO.PrimaryVertexToHit))
823 {
824 if(Debug2){cout << "firstDaughterRECO.timedDistanceToHit[" << 1 << "]: " << firstDaughterRECO.timedDistanceToHit[medium] << ", firstDaughterRECO.PrimaryVertexToHit: " << firstDaughterRECO.PrimaryVertexToHit << endl
825 << "secondDaughterRECO.timedDistanceToHit[" << 1 << "]: " << secondDaughterRECO.timedDistanceToHit[medium] << ", secondDaughterRECO.PrimaryVertexToHit: " << secondDaughterRECO.PrimaryVertexToHit << endl
826 << "Cannot construct displaced vertex" << endl;}
827
828 numberOfZsWithoutTwoPositiveTimes++;
829 return; // Exit without making any plots
830 }
831 // else: calculate an initial value for the displaced vertex (i.e. the parent particle's flight length)
832
833 if(Debug2){cout << "Looking for displaced vertex" << endl;}
834 Parent.flightLength[medium] = findDisplacedVertexLength(firstDaughterRECO, 1, secondDaughterRECO, 1);
835 if (Parent.flightLength[medium] == dummy) // displaced vertex algorithm never converged.
836 {
837 return; // Without setting any values for reconstructed mass
838 }
839 numberOfDisplacedVertices++;
840 if(Debug2){cout << "Initial flight length: " << Parent.flightLength[medium] << endl;}
841
842 // Find the parent's mass, energy & hence gamma
843 // m = sqrt[2*E(1) * E(2)*(1-cos(theta)] where 'theta' is the included angle between the 2 electron hits
844 // firstDaughterRECO.omega: Angle between firstDaughterRECO electron hit, primary vertex and displaced vertex
845 // secondDaughterRECO.omega: Angle between secondDaughterRECO electron hit, primary vertex and displaced vertex
846 // if(Debug2){cout << "firstDaughterRECO omega[" << 1 << "]: " << firstDaughterRECO.omega[medium] << ", secondDaughterRECO omega[" << 1 << "]: " << secondDaughterRECO.omega[medium] << endl;}
847
848 if(Debug2){cout << "firstDaughterRECO.flightLength[medium]: " << firstDaughterRECO.flightLength[medium] << ", Parent.flightLength[medium]: " << Parent.flightLength[medium] << ",firstDaughterRECO.PrimaryVertexToHit: " << firstDaughterRECO.PrimaryVertexToHit << endl;}
849 if(Debug2){cout << "secondDaughterRECO.flightLength[medium]: " << secondDaughterRECO.flightLength[medium] << ", Parent.flightLength[medium]: " << Parent.flightLength[medium] << ",secondDaughterRECO.PrimaryVertexToHit: " << secondDaughterRECO.PrimaryVertexToHit << endl;}
850
851 // angleBetweenHits = 2*pi - (angle between PV->DV->Hit1) - (angle between PV->DV->Hit2)
852
853 float angleBetweenPrimaryVertexDisplacedVertexHitOne = getAngle(firstDaughterRECO.flightLength[medium],Parent.flightLength[medium],firstDaughterRECO.PrimaryVertexToHit);
854 float angleBetweenPrimaryVertexDisplacedVertexHitTwo = getAngle(secondDaughterRECO.flightLength[medium],Parent.flightLength[medium],secondDaughterRECO.PrimaryVertexToHit);
855 if(Debug2){cout << "initial angleBetweenPrimaryVertexDisplacedVertexHitOne: " << angleBetweenPrimaryVertexDisplacedVertexHitOne << endl;}
856 if(Debug2){cout << "initial angleBetweenPrimaryVertexDisplacedVertexHitTwo: " << angleBetweenPrimaryVertexDisplacedVertexHitTwo << endl;}
857
858 float AngleBetweenHits = (2*pi) - angleBetweenPrimaryVertexDisplacedVertexHitOne -angleBetweenPrimaryVertexDisplacedVertexHitTwo;
859 if(Debug2){cout << "Initial AngleBetweenHits: " << AngleBetweenHits << endl;}
860 // Reconstructed mass is ~ zero for very small angles
861 if (AngleBetweenHits < minimumAngleBetweenElectrons)
862 {
863 minimumAngleBetweenElectronsRejects++;
864 return;
865 }
866 if (Debug2) {cout << "firstDaughterRECO.energy: " << firstDaughterRECO.energy << ", secondDaughterRECO.energy: " << secondDaughterRECO.energy << endl;}
867
868 Parent.mass[medium] = sqrt(2.0 * firstDaughterRECO.energy * secondDaughterRECO.energy * (1 - cos(AngleBetweenHits)));
869 Parent.energy = firstDaughterRECO.energy + secondDaughterRECO.energy;
870 if (Debug2) {cout << "Parent.mass[medium]: " << Parent.mass[medium] << ", Parent.energy: " << Parent.energy << endl;}
871
872
873 // Parent.gamma[medium] = Parent.energy / Parent.mass[medium];
874
875 // Now iterate: modify the constructed parent's flight length to allow for the current calculated mass of the constructed parent
876 // The angles between the hits will initially remain constant as we modify the displaced vertex length (for the mass of the LL) and electron path length
877
878 // firstDaughterRECO.flightLength[medium] = firstDaughterRECO.timedDistanceToHit[medium] - Parent.flightLength[medium];
879 // secondDaughterRECO.flightLength[medium] = secondDaughterRECO.timedDistanceToHit[medium] - Parent.flightLength[medium];
880
881 int count = 0;
882 float oldConstructedParentMass = dummy; // arbitrary initial value
883 float deltaTime = 1.0; // arbitrary initial value
884 float firstDeltaTime;
885 float secondDeltaTime;
886 // float deltaOmega; // Incremental change to omega for both daughters
887
888 // Calculate initial value for reconstructed mass
889 // Initial approximation assumed a LL mass of zero and velocity of c
890 // Parent.mass[medium] = sqrt(2.0 * firstDaughterRECO.energy * secondDaughterRECO.energy * (1 - cos(AngleBetweenHits)));
891
892 if(Debug2){cout << endl << "Finding new reconstructed mass" << endl;}
893 // while ( (fabs(oldConstructedParentMass - Parent.mass[medium] ) > deltaConstructedMass) && (count < 100))
894 float deltaOmega = (firstDaughterRECO.omega[medium] + secondDaughterRECO.omega[medium])/5;// Only a small change required
895
896 while ( (fabs(deltaTime ) > 0.2) && (count < 100))
897 {
898 oldConstructedParentMass = Parent.mass[medium];
899 count++;
900 // Now modify result for a LL mass > 0, and LL velocity < c
901 // Use the LL energy & mass to calculate its gamma, and hence velocity
902 if (Parent.mass[medium] != 0)
903 {
904 Parent.gamma[medium] = Parent.energy / Parent.mass[medium];
905 }
906 else
907 {
908 Parent.gamma[medium] = 1000; // arbitrary large value
909 }
910
911 if (Debug2) {cout << "count: " << count << ", LLGamma: " << Parent.gamma[medium] << endl;}
912 // Find the LLvelocity
913 if (Parent.gamma[medium] < 1000)
914 {
915 Parent.velocity = speedOfLight_*sqrt(1 - 1/(Parent.gamma[medium] * Parent.gamma[medium]));
916 if(Debug2){cout << "Constructed parent velocity: " << Parent.velocity << endl;}
917 }
918 else
919 {
920 Parent.velocity = speedOfLight_; // If gamma = infinity, velocity = speedOfLight_
921 }
922 // Using the LL velocity calculate the expected flight times and compare with the measured time
923 // Calculate the hit time for each electron, being constructed parent flight time + electron flight time
924 // For firstDaughterRECO electron
925 float firstConstructedTimeOfFlight = (Parent.flightLength[medium]/Parent.velocity) + (firstDaughterRECO.flightLength[medium]/speedOfLight_);
926 if(Debug2){cout << "firstConstructedTimeOfFlight: " << firstConstructedTimeOfFlight << ", firstDaughterRECO.measuredHitTime[medium]: " << (firstDaughterRECO.PrimaryVertexToHit/speedOfLight_) + firstDaughterRECO.measuredHitTime[medium] << endl;}
927 float secondConstructedTimeOfFlight = (Parent.flightLength[medium]/Parent.velocity) + (secondDaughterRECO.flightLength[medium]/speedOfLight_);
928 if(Debug2){cout << "secondConstructedTimeOfFlight: " << secondConstructedTimeOfFlight << ",secondDaughterRECO.measuredHitTime[medium]: " << (secondDaughterRECO.PrimaryVertexToHit/speedOfLight_) + secondDaughterRECO.measuredHitTime[medium] << endl;}
929
930 // Find difference in calculated and measured flight times
931 // Note - the measured time is the excess over the time a relativistic particle would take.
932 firstDeltaTime = firstConstructedTimeOfFlight - (firstDaughterRECO.PrimaryVertexToHit/speedOfLight_ + firstDaughterRECO.measuredHitTime[medium]);
933 secondDeltaTime = secondConstructedTimeOfFlight - (secondDaughterRECO.PrimaryVertexToHit/speedOfLight_ + secondDaughterRECO.measuredHitTime[medium]);
934 // deltaTime = fabs(firstDeltaTime) + fabs(secondDeltaTime);
935 deltaTime = fabs(firstDeltaTime) + fabs(secondDeltaTime);
936 if(Debug2){cout << "firstDeltaTime: " << firstDeltaTime << ", secondDeltaTime: " << secondDeltaTime << ", deltaTime: " << deltaTime << endl;}
937
938 // Modify displaced vertex length based upon the average deltaTime for both electrons
939 if ((firstDeltaTime * secondDeltaTime) > 0) // If delta times are of the same sign
940 {
941 // A contrieved algorithm to modify parent flight length. Maybe a better algorithm could be used
942 if(Debug2){cout << "firstDaughterRECO.measuredHitTime[medium]: " << firstDaughterRECO.measuredHitTime[medium] << endl;}
943 if(Debug2){cout << "secondDaughterRECO.measuredHitTime[medium]: " <<secondDaughterRECO.measuredHitTime[medium] << endl;}
944 if(Debug2){cout << "Old Parent.flightLength[medium]: " << Parent.flightLength[medium] << endl;}
945
946 // Adjust parent flight length by ratio of (difference of measured time) to (total flight time)
947 // Factor of "2*" gives faster convergence
948 // If the calculated time > measured, then the slow parent flight length must be shorter, and the fast daughters' length longer
949 // Parent.flightLength[medium] = Parent.flightLength[medium] * (1 - (10* deltaTime)/(firstDaughterRECO.PrimaryVertexToHit/speedOfLight_ + firstDaughterRECO.measuredHitTime[medium] + secondDaughterRECO.PrimaryVertexToHit/speedOfLight_ + secondDaughterRECO.measuredHitTime[medium]));
950 Parent.flightLength[medium] = Parent.flightLength[medium] * (1 - (firstDeltaTime + secondDeltaTime));
951 }
952
953 if (Debug2) {cout << "New displacedVertexLength: " << Parent.flightLength[medium] << endl;}
954
955 // Now modify the direction of the parent flight path between the two particle hits
956 // if one deltaTime is +ve & the other -ve then slightly rotate the parentMC path around the primary vertex
957
958 if ((firstDeltaTime * secondDeltaTime) < 0.0) // Only if times are of the opposite sign
959 {
960 if(Debug2){cout << "Opposite sign delta times" << endl;}
961 deltaOmega = deltaOmega/2;// Only a small change required
962 // float deltaOmega = 0.1; // Only a small change required
963 // Algorithm to modify angle. delta time will be small wrt actual times of flight
964 // float deltaOmega = firstDaughterRECO.omega[medium] * (1 - (deltaTime/(firstDaughterRECO.PrimaryVertexToHit/speedOfLight_ + firstDaughterRECO.measuredHitTime[medium] + secondDaughterRECO.PrimaryVertexToHit/speedOfLight_ + secondDaughterRECO.measuredHitTime[medium])));
965 if(Debug2){cout << "Old firstDaughterRECO omega[" << 1 << "]: " << firstDaughterRECO.omega[medium] << ", Old secondDaughterRECO omega[" << 1 << "]: " << secondDaughterRECO.omega[medium] << ", deltaOmega: " << deltaOmega << endl;}
966
967 if((firstDeltaTime > 0.0) && (secondDeltaTime < 0.0))
968 {
969 // If constructed flight time > true flight time, then increase electron path length i.e path of faster particle
970 // angle between ECAL hit to primary vertex to displaced vertex for daughter particles
971 if (Debug2){cout << "here first" << endl;}
972 firstDaughterRECO.omega[medium] = firstDaughterRECO.omega[medium] - deltaOmega;
973 secondDaughterRECO.omega[medium] = secondDaughterRECO.omega[medium] + deltaOmega;
974 }
975 else if((firstDeltaTime < 0.0) && (secondDeltaTime > 0.0))
976 {
977 if (Debug2){cout << "here second" << endl;}
978 // If constructed flight time < true flight time, then decrease electron path length i.e path of faster particle
979 firstDaughterRECO.omega[medium] = firstDaughterRECO.omega[medium] + deltaOmega;
980 secondDaughterRECO.omega[medium] = secondDaughterRECO.omega[medium] - deltaOmega;
981 }
982 if(Debug2){cout << "New firstDaughterRECO omega[" << 1 << "]: " << firstDaughterRECO.omega[medium] << ", New secondDaughterRECO omega[" << 1 << "]: " << secondDaughterRECO.omega[medium] << endl;}
983 }
984
985
986 // Adjust path lengths for both electrons for the change in displaced vertex and angle omega
987 firstDaughterRECO.flightLength[medium] = getOppositeLength (Parent.flightLength[medium], firstDaughterRECO.PrimaryVertexToHit, firstDaughterRECO.omega[medium]);
988 secondDaughterRECO.flightLength[medium] = getOppositeLength (Parent.flightLength[medium], secondDaughterRECO.PrimaryVertexToHit, secondDaughterRECO.omega[medium]);
989 if(Debug2){cout << "firstDaughterRECO.flightLength[medium]: " << firstDaughterRECO.flightLength[medium] << ",secondDaughterRECO.flightLength[medium]: " << secondDaughterRECO.flightLength[medium] << endl;}
990
991 // Now recalculate the angle between hits
992 angleBetweenPrimaryVertexDisplacedVertexHitOne = getAngle(firstDaughterRECO.flightLength[medium],Parent.flightLength[medium],firstDaughterRECO.PrimaryVertexToHit);
993 angleBetweenPrimaryVertexDisplacedVertexHitTwo = getAngle(secondDaughterRECO.flightLength[medium],Parent.flightLength[medium],secondDaughterRECO.PrimaryVertexToHit);
994 if(Debug2){cout << "angleBetweenPrimaryVertexDisplacedVertexHitOne: " << angleBetweenPrimaryVertexDisplacedVertexHitOne << endl;}
995 if(Debug2){cout << "angleBetweenPrimaryVertexDisplacedVertexHitTwo: " << angleBetweenPrimaryVertexDisplacedVertexHitTwo << endl;}
996
997 AngleBetweenHits = (2*pi) - angleBetweenPrimaryVertexDisplacedVertexHitOne - angleBetweenPrimaryVertexDisplacedVertexHitTwo;
998
999 if (Debug2) {cout << "AngleBetweenHits : " << AngleBetweenHits << endl;}
1000
1001 // Recalculate reconstructed mass
1002 // Initial approximation assumed a LL mass of zero and velocity of c
1003 Parent.mass[medium] = sqrt(2.0 * firstDaughterRECO.energy * secondDaughterRECO.energy * (1 - cos(AngleBetweenHits)));
1004 Parent.omega[medium] = AngleBetweenHits;
1005 if (Debug2) {cout << "Revised reconstructed mass[medium]: " << Parent.mass[medium] << endl;}
1006
1007 // Store values for Graph with asymm errors
1008 // bestMass[ErrorsCount] = Parent.mass[medium];
1009 // bestFlightLength[ErrorsCount] = Parent.flightLength[medium];
1010
1011 ErrorsCount++;
1012 if (Debug2 && (count >= 100)) {cout << "Count: " << count << endl;}
1013 }
1014
1015 if (Debug2){cout << "Parent.flightLength[medium]: " << Parent.flightLength[medium] << endl;}
1016 if (Parent.flightLength[medium] < 0.0)
1017 {
1018 nonPhysicalDecayLength++;
1019 }
1020 if (Parent.flightLength[medium] >= 0.0) // Flight length < 0 is non-physical
1021 {
1022 if (Debug2){cout << "Parent.mass[medium]: " << Parent.mass[medium] << endl;}
1023 if (Debug2){cout << "Parent.flightLength[medium]: " << Parent.flightLength[medium] << endl;}
1024
1025 if(Debug2){cout << "massCalcCounter: " << massCalcCounter << endl;}
1026 massCalcCounter++;
1027 if (AngleBetweenHits > minimumAngleBetweenElectrons) // Very small angles between electrons has large errors
1028 {
1029 hists_["t1"]->Fill(Parent.mass[medium]);
1030 if(Debug2){cout << "t1 OK" << endl;}
1031 hists_["t2"]->Fill(Parent.flightLength[medium]);
1032 if(Debug2){cout << "t2 OK" << endl;}
1033 hists_["t5"]->Fill(Parent.mass[medium], Parent.flightLength[medium]); // Reconstructed mass vs constructed LL flight length
1034 if(Debug2){cout << "t5 OK" << endl;}
1035 hists_["t9"]->Fill(Parent.mass[medium], Parent.flightLength[medium]); // Profile plot of reconstructed mass vs constructed LL flight length
1036 if(Debug2){cout << "t9 OK" << endl;}
1037 //hists_["t11"]->Fill(Parent.mass[medium], Parent.mass[medium] - Parent.mass[medium]); // Profile plot of True (MC) mass vs True mass - constructed mass
1038 // if(Debug2){cout << "t11 OK" << endl;}
1039
1040 // Plot daughter's hit time vs constructed flight length
1041 if(Debug2){cout << "firstDaughterRECO.measuredHitTime[" << 1 << "]: " << firstDaughterRECO.measuredHitTime[medium] << ", parentMC.flightLength[" << 1 << "]: " << Parent.flightLength[medium] << endl;}
1042 if (firstDaughterRECO.measuredHitTime[medium] != dummy) // Only plot measured hit times
1043 {
1044 hists_["t7"]->Fill(firstDaughterRECO.measuredHitTime[medium], Parent.flightLength[medium]); // firstDaughterRECO.measuredHitTime vs parentMC constructed flight length
1045 }
1046 if (secondDaughterRECO.measuredHitTime[medium] != dummy) // Only plot measured hit times
1047 {
1048 hists_["t7"]->Fill(secondDaughterRECO.measuredHitTime[medium], Parent.flightLength[medium]); // secondDaughterRECO.measuredHitTime vs parentMC constructed flight length
1049 }
1050 }
1051 }
1052 if(Debug2) {cout << "Constructed displaced vertex[medium]: " << Parent.flightLength[medium] << " cm" << endl; }
1053 return;
1054 }
1055
1056 // Take two hits. Return the displaced vertex shared by the two hits
1057 float
1058 RecoFirst::findDisplacedVertexLength(myParticle &firstDaughterRECO, int i, myParticle &secondDaughterRECO, int j)
1059 // Using polar coords for the ellipses. The Primary Vertex is a shared focus. Each hit is the other focus for each ellipse.
1060 // The flight time for each hit is the twice major axis for each ellipse.
1061 // Equations for ellipse using polar coords from one focus:
1062 // r(theta) = a*(1-eta*eta)/(1 +- eta * cos(theta))
1063 // We will always use r(theta) = a*(1-eta*eta)/(1 + eta * cos(theta)) This is correct, and has been validated with an Excel plot
1064 // For each ellipse:
1065 // eta = f/a,
1066 // with f = 1/2 * distance between foci (i.e. half the distance between PV & hit)
1067 // a = major axis, i.e. half of flight time distance ... flight time distance = f + a + (a-f) = 2a
1068 // As an initial value assume displaced vertex is angled half way between the two ellipses, then theta1 = alhpa/2
1069 {
1070 float decayLength1 = 1.0; // Arbitrary initial value for decay length for first ellipse
1071 float decayLength2 = 10.0; // Arbitrary initial value for decay length for second ellipse
1072 // We want DecayLength1 = DecayLength2 at a shared displaced vertex
1073
1074 float InitialAngleBetweenHits = getInitialAngleBetweenLeptons(firstDaughterRECO, secondDaughterRECO);
1075
1076 // Reject cases where the two electrons are very close together
1077 if (fabs(InitialAngleBetweenHits) < minimumAngleBetweenElectrons)
1078 {
1079 decayLength1 = dummy; // return a negative decay length
1080 firstDaughterRECO.omega[i] = dummy;
1081 secondDaughterRECO.omega[j] = dummy;
1082 return dummy;
1083 }
1084
1085 // We want DecayLength1 = DecayLength2 at a shared displaced vertex
1086 float omega1 = InitialAngleBetweenHits/2.0; // Give omega1 & omega2 aribitrary starting values (in radians)
1087 float omega2 = InitialAngleBetweenHits/2.0;
1088 int count = 0;
1089 float deltaOmega1 = omega1/2.0;
1090
1091 // For first ellipse
1092 float a1 = firstDaughterRECO.timedDistanceToHit[i]/2.0;
1093 float f1 = firstDaughterRECO.PrimaryVertexToHit/2.0;
1094 float eta1 = f1/a1;
1095 if (Debug2) {cout << "Major axis 1: " << a1 << ", foci1: " << f1 << ", eta1: " << eta1 << endl;}
1096
1097 // For second ellipse
1098 float a2 = secondDaughterRECO.timedDistanceToHit[j]/2.0;
1099 float f2 = secondDaughterRECO.PrimaryVertexToHit/2.0;
1100 float eta2 = f2/a2;
1101 if (Debug2) {cout << "Major axis 2: " << a2 << ", foci2: " << f2 << ", eta2: " << eta2 << endl;}
1102
1103 // Loop until ratio of difference in decay lengths < decayLengthAccuracy i.e. 1%
1104 while ( (fabs((decayLength1-decayLength2)/(decayLength1 + decayLength2)) > decayLengthAccuracy) && (count < 100) && (deltaOmega1 > minDeltaOmega))
1105 {
1106 if (Debug2) {cout << "count: " << count << ", omega1: " << omega1 << ", omega2: " << omega2 << endl;}
1107
1108 decayLength1 = a1*(1-eta1*eta1)/(1 + eta1*cos(omega1));
1109 if (Debug2){cout << "a1: " << a1 << ", eta1: " << eta1 << ", decayLength1 = a1*(1-eta1*eta1)/(1 + eta1*cos(omega1)): " << decayLength1 << endl;}
1110
1111 if (Debug2) {cout << "omega1: " << omega1 << ", displaced vertex 1: " << decayLength1 << endl;}
1112
1113 decayLength2 = a2*(1-eta2*eta2)/(1 + eta2*cos(omega2));
1114 if (Debug2){cout << "a2: " << a2 << ", eta2: " << eta2 <<", decayLength2 = a2*(1-eta2*eta2)/(1 + eta2*cos(omega2)):" << decayLength2 << endl;}
1115
1116 if (Debug2) {cout << "omega2: " << omega2 << ", displaced vertex 2: " << decayLength2 << endl;}
1117
1118 // compare decayLength1 & decayLength2
1119 if (decayLength1 > decayLength2)
1120 {
1121 omega1 = omega1 - deltaOmega1;
1122 //omega1 = omega1 + deltaOmega1;
1123 if (Debug2) {cout << "Length1 > Length2, so omega1: " << omega1 << ", deltaOmega1: " << deltaOmega1 << endl;}
1124 }
1125 if (decayLength1 < decayLength2)
1126 {
1127 omega1 = omega1 + deltaOmega1;
1128 // omega1 = omega1 - deltaOmega1;
1129 if (Debug2) {cout << "Length1 < Length2, so omega1: " << omega1 << ", deltaOmega1: " << deltaOmega1 << endl;}
1130 }
1131 omega2 = InitialAngleBetweenHits - omega1;
1132 deltaOmega1 = deltaOmega1/2.0;
1133 if (Debug2) {cout << "deltaOmega1: " << deltaOmega1 << ", omega2: " << omega2 << endl;}
1134
1135 // else if decayLength1 = decayLength2, do nothing
1136 ++count;
1137 }
1138 if (Debug2) { cout << "Final calculated decay length is: " << decayLength1 << ", omega1: " << omega1 << ", omega2: " << omega2<< endl << endl;}
1139 firstDaughterRECO.omega[i] = omega1;
1140 secondDaughterRECO.omega[j] = omega2;
1141 firstDaughterRECO.flightLength[i] = getOppositeLength(decayLength1, firstDaughterRECO.PrimaryVertexToHit, omega1);
1142 secondDaughterRECO.flightLength[j] = getOppositeLength(decayLength1, secondDaughterRECO.PrimaryVertexToHit, omega2);
1143 if(Debug2){cout << "firstDaughterRECO.omega: " << omega1 << ", firstDaughterRECO.flightLength[" << i << "]: " << firstDaughterRECO.flightLength[i] << endl;}
1144 if(Debug2){cout << "secondDaughterRECO.omega: " << omega2 << ", secondDaughterRECO.flightLength[" << j << "]: " << secondDaughterRECO.flightLength[j] << endl;}
1145
1146 if ((firstDaughterRECO.omega[i] == 0) || (secondDaughterRECO.omega[j] == 0) ) // algorithm never converged
1147 {
1148 noDisplacedVertexConvergence++;
1149 decayLength1 = dummy; // return a negative decay length
1150 firstDaughterRECO.omega[i] = dummy;
1151 secondDaughterRECO.omega[j] = dummy;
1152 }
1153 hists_["t21"]->Fill(firstDaughterRECO.PrimaryVertexToHit); // firstDaughterRECO PrimaryVertexToHit
1154 hists_["t22"]->Fill(secondDaughterRECO.PrimaryVertexToHit); // secondDaughterRECO PrimaryVertexToHit
1155
1156 // Simply take half the average distance for the two electrons
1157 // hists_["t20"]->Fill((firstDaughterRECO.PrimaryVertexToHit + secondDaughterRECO.PrimaryVertexToHit)/4.0); // Initial flight length estimate
1158 // return (firstDaughterRECO.PrimaryVertexToHit + secondDaughterRECO.PrimaryVertexToHit)/4.0;
1159 hists_["t20"]->Fill(decayLength1); // Initial flight length estimate
1160 return decayLength1;
1161
1162 }
1163
1164 // Get daughter particle energy, ECAL hit time, hit position and distance of hit from primary vertex
1165 // The daughter particles are 'passed by reference' so their parameters are updated
1166 template <class photonType> void
1167 RecoFirst::getDaughterParameters (myParticle &daughterParticle, photonType photon)
1168 {
1169 if(Debug2){cout << endl << "Get new daughter" << endl;}
1170 // Reset values to ensure previous values are not retained
1171 daughterParticle.energy = dummy;
1172 daughterParticle.pt = dummy;
1173 daughterParticle.et = dummy;
1174 daughterParticle.eta = dummy;
1175 daughterParticle.phi = dummy;
1176 daughterParticle.measuredHitTime[medium] = dummy;
1177 daughterParticle.timedDistanceToHit[medium] = dummy;
1178 daughterParticle.PrimaryVertexToHit = dummy;
1179
1180 if (photon->superCluster().isNull() )
1181 {
1182 return;
1183 }
1184
1185 daughterParticle.energy = photon->energy();
1186 daughterParticle.pt = photon->pt();
1187 daughterParticle.et = photon->et();
1188 daughterParticle.eta = photon->eta();
1189 daughterParticle.phi = photon->phi();
1190 if(Debug2){cout << "Lepton energy: " << daughterParticle.energy << endl;}
1191
1192 // Use the DetId of the photon to find the time of the ECAL hit
1193 // Then get the time of the crystal with the maximum hit energy
1194
1195 EBRecHitCollection::const_iterator EBRecHitItr;
1196 EERecHitCollection::const_iterator EERecHitItr;
1197
1198 EcalRecHit EcalHit;
1199 // reducedEcalRecHitsEB EcalHitEB; // AOD modification
1200 // reducedEcalRecHitsEE EcalHitEE;
1201
1202 float MaxEcalHitEnergy = 0.0; // Initialisation value
1203
1204 // The photon's superCluster returns a collection of crystals' DetId and energy as a fraction of the total energy
1205 const vector< pair < DetId, float > > PhotonHitsAndFraction = photon->superCluster()->hitsAndFractions();
1206 // Loop over the crystals in the cluster to get a DetId for each crystal
1207 for (unsigned HitIndex = 0; HitIndex < PhotonHitsAndFraction.size(); ++HitIndex)
1208 {
1209 const DetId PhotonHit = PhotonHitsAndFraction[HitIndex].first; // 'first' here defeines the CMSSW parameter 'Hits'
1210 // Look for a hit in the Ecal barrel or endcap that matches the photon hit from the cluster
1211 EBRecHitItr = EBhits_->find(PhotonHit);
1212
1213 if (EBRecHitItr != EBhits_->end()) // We have a hit in the barrel
1214 {
1215 EcalHit = (*EBRecHitItr);
1216 // EcalHitEB = (*EBRecHitItr); // AOD modification
1217 }
1218 else // Look for a hit in the endcap that matches the photon hit
1219 {
1220 EERecHitItr = EEhits_->find(PhotonHit);
1221 if (EERecHitItr != EEhits_->end()) // We have a hit in the endcap
1222 {
1223 EcalHit = (*EERecHitItr);
1224 // EcalHitEE = (*EBRecHitItr); // AOD modification
1225
1226 }
1227 }
1228 // If we have a hit in either the Ecal barrel or endcap
1229 // Get the hit time for the crystal with the largest energy
1230 if ((EBRecHitItr != EBhits_->end()) || (EERecHitItr != EEhits_->end()))
1231 {
1232 if ((EcalHit.energy() > MaxEcalHitEnergy) && (EcalHit.energy() > crystalMinEnergy)) // Get the hit time for the crystal with the greatest energy
1233 {
1234 MaxEcalHitEnergy = EcalHit.energy();
1235 daughterParticle.measuredHitTime[medium] = EcalHit.time();
1236 }
1237 }
1238 }
1239
1240 // Now populate the measuredHitTime error values
1241 // [low] is minimim, [medium] is measured, [high] is maximum
1242 // In barrel if |eta| < 1.44
1243 // If hit in barrel error +- 0.27ns. If in endcap error +- 0.18ns
1244 if (fabs(daughterParticle.eta) <= barrelLimit)
1245 {
1246 daughterParticle.measuredHitTime[low] = daughterParticle.measuredHitTime[medium] - barrelTimingError;
1247 daughterParticle.measuredHitTime[high] = daughterParticle.measuredHitTime[medium] + barrelTimingError;
1248 }
1249 else // Must be in endcap
1250 {
1251 daughterParticle.measuredHitTime[low] = daughterParticle.measuredHitTime[medium] - endcapTimingError;
1252 daughterParticle.measuredHitTime[high] = daughterParticle.measuredHitTime[medium] + endcapTimingError;
1253 }
1254
1255 if(Debug2)
1256 {
1257 if (daughterParticle.measuredHitTime[medium] == dummy) // Show particles with no times set
1258 {
1259 cout << "particle eta: " << daughterParticle.eta << endl
1260 << "daughterParticle.measuredHitTime[low]: " << daughterParticle.measuredHitTime[low] << endl
1261 << "daughterParticle.measuredHitTime[medium]: " << daughterParticle.measuredHitTime[medium] << endl
1262 << "daughterParticle.measuredHitTime[high]: " << daughterParticle.measuredHitTime[high] << endl;
1263 }
1264 }
1265
1266 int a = 0;
1267 if (measured) {a=1;}
1268 else if (minimum) {a=0;}
1269 else if (maximum) {a=2;}
1270
1271 // Distance from primary vertex to photon hit
1272 daughterParticle.endPoint = photon->caloPosition(); // Where the photon hits the ECAL
1273 math::XYZPoint PrimaryVertexToHit;
1274 PrimaryVertexToHit = daughterParticle.endPoint - PrimaryVertex_;
1275 float x = PrimaryVertexToHit.x();
1276 float y = PrimaryVertexToHit.y();
1277 float z = PrimaryVertexToHit.z();
1278 daughterParticle.PrimaryVertexToHit = sqrt(x*x + y*y + z*z);
1279 // daughterParticle.timedDistanceToHit[medium] = daughterParticle.PrimaryVertexToHit + (daughterParticle.measuredHitTime[medium] * speedOfLight_);
1280 // CMSSW time = 0.0 is for flight from the IP, NOT from primary vertex.
1281 // So must account for IP to primary vertex displacement
1282 // Find distance (from IP to hit) + distance for hit time
1283 // Note: IP is at (0,0,0)
1284 // TimedDistance is time * speed of light (30 cm/ns)
1285 x = daughterParticle.endPoint.x();
1286 y = daughterParticle.endPoint.y();
1287 z = daughterParticle.endPoint.z();
1288 float IpToHitPlusTimeDistance [3];
1289 for (int i=0; i<3; i++)
1290 {
1291 IpToHitPlusTimeDistance [i]= sqrt(x*x + y*y + z*z) + (daughterParticle.measuredHitTime[i] * speedOfLight_);
1292 }
1293 // Distance from IP to primary vertex
1294 x = PrimaryVertex_.x();
1295 y = PrimaryVertex_.y();
1296 z = PrimaryVertex_.z();
1297 float IpToPrimaryVertex = sqrt(x*x + y*y + z*z);
1298 // Angle between hit->IP->primary vertex
1299 TVector3 x1;
1300 TVector3 x0;
1301 x0.SetXYZ(daughterParticle.endPoint.x(), daughterParticle.endPoint.y(), daughterParticle.endPoint.z() );
1302 x1.SetXYZ(PrimaryVertex_.x(), PrimaryVertex_.y(), PrimaryVertex_.z());
1303 float hitToIpToPrimaryVertexAngle = x0.Angle(x1);
1304 // Using the cosine rule and knowing two sides of a triangle and the included angle
1305 // c = sqrt(a*a + b*b - 2*a*b*cos(theta))
1306 for (int i=0; i<3; i++)
1307 {
1308 float a = IpToHitPlusTimeDistance[i];
1309 float b = IpToPrimaryVertex;
1310 // float c = sqrt(a*a + b*b - 2*a*b*cos(hitToIpToPrimaryVertexAngle));
1311 daughterParticle.timedDistanceToHit[i] = sqrt(a*a + b*b - 2*a*b*cos(hitToIpToPrimaryVertexAngle));
1312 if (Debug2){cout << "timedDistanceToHit[" << i << "]: " << daughterParticle.timedDistanceToHit[i] << ", PrimaryVertexToHit: " << daughterParticle.PrimaryVertexToHit << endl;}
1313 }
1314 return;
1315 }
1316
1317 // Get daughter particle statistics: energy, ECAL hit time, hit position and distance of hit from primary vertex
1318 // The daughter particles are 'passed by reference' so their parameters are updated
1319 template <class photonType> void
1320 RecoFirst::getDaughterStats (myParticle &daughterParticle, photonType photon)
1321 {
1322 numberOfDaughters++;
1323
1324 if (photon->superCluster().isNull() )
1325 {
1326 nullSuperClusters++;
1327 return;
1328 }
1329
1330 // Use the DetId of the photon to find the time of the ECAL hit
1331 // Then get the time of the crystal with the maximum hit energy
1332
1333 EBRecHitCollection::const_iterator EBRecHitItr;
1334 EERecHitCollection::const_iterator EERecHitItr;
1335 EcalRecHit EcalHit;
1336 float MaxEcalHitEnergy = 0.0; // Initialisation value
1337
1338 // The photon's superCluster returns a collection of crystals' DetId and energy as a fraction of the total energy
1339 const vector< pair < DetId, float > > PhotonHitsAndFraction = photon->superCluster()->hitsAndFractions();
1340 // Loop over the crystals in the cluster to get a DetId for each crystal
1341 for (unsigned HitIndex = 0; HitIndex < PhotonHitsAndFraction.size(); ++HitIndex)
1342 {
1343 const DetId PhotonHit = PhotonHitsAndFraction[HitIndex].first; // 'first' here defines the CMSSW parameter 'Hits'
1344 // Look for a hit in the Ecal barrel or endcap that matches the photon hit from the cluster
1345 EBRecHitItr = EBhits_->find(PhotonHit);
1346
1347 if (EBRecHitItr != EBhits_->end()) // We have a hit in the barrel
1348 {
1349 EcalHit = (*EBRecHitItr);
1350 }
1351 else // Look for a hit in the endcap that matches the photon hit
1352 {
1353 EERecHitItr = EEhits_->find(PhotonHit);
1354 if (EERecHitItr != EEhits_->end()) // We have a hit in the endcap
1355 {
1356 EcalHit = (*EERecHitItr);
1357 }
1358 }
1359 // If we have a hit in either the Ecal barrel or endcap
1360 // Get the hit time for the crystal with the largest energy
1361 if ( (EBRecHitItr != EBhits_->end()) || (EERecHitItr != EEhits_->end()) )
1362 {
1363 if (EcalHit.energy() > MaxEcalHitEnergy) // Get the hit time for the crystal with the greatest energy
1364 {
1365 MaxEcalHitEnergy = EcalHit.energy();
1366 if (EcalHit.energy() > crystalMinEnergy) // crystal energy below this minimum has very bad timing resolution
1367 {
1368 daughterParticle.measuredHitTime[medium] = EcalHit.time();
1369 }
1370 else
1371 {
1372 daughterParticle.measuredHitTime[medium] = dummy; // Make this a negative value so don't retain the previous value
1373 }
1374 }
1375 }
1376 }
1377 if(Debug2){cout << "daughterParticle.measuredHitTime[medium]: " << daughterParticle.measuredHitTime[medium] << endl;}
1378 if (daughterParticle.measuredHitTime[medium] == dummy)
1379 {
1380 lowCrystalHitEnergy++;
1381 }
1382 if ((daughterParticle.measuredHitTime[medium] < 0.0) && (daughterParticle.measuredHitTime[medium] != dummy))
1383 {
1384 negativeHitTime++;
1385 }
1386
1387 if (daughterParticle.measuredHitTime[medium] != dummy) // Don't plot dummy values when crystal energy below minimum
1388 {
1389 hists_["t8"]->Fill(daughterParticle.measuredHitTime[medium]);
1390 }
1391 return;
1392 }
1393
1394
1395 float
1396 RecoFirst::calcDeltaPhi(float phi1, float phi2)
1397 {
1398 // Calculate the difference between phi1 & phi2
1399 // Phi ranges from 0 to +pi and 0 to -pi
1400 // deltaPhi lies between 0 to pi
1401 float deltaPhi;
1402 if (Debug2) {cout << "phi1: " << phi1 << ", phi2: " << phi2 << endl;}
1403 if (phi1 < 0) {phi1 = (2.0 * pi) + phi1;}
1404 if (phi2 < 0) {phi2 = (2.0 * pi) + phi2;}
1405 deltaPhi = fabs(phi1 - phi2);
1406 if (deltaPhi > pi) {deltaPhi = (2.0 * pi) - deltaPhi;}
1407 if (Debug2) { cout << "phi1: " << phi1 << ", phi2: " << phi2 << ", deltaPhi: " << deltaPhi << endl;}
1408 return deltaPhi;
1409 }
1410
1411 float
1412 RecoFirst::calcDeltaEta(float eta1, float eta2)
1413 {
1414 // Calculates the difference between eta1 & eta2
1415 // eta ranges from -10 to + 10 (or anyway - a large value and we don't care beyond abs(2.5))
1416 float deltaEta;
1417 if ( ((eta1 <= 0.0) && (eta2 <= 0.0)) || ((eta1 >= 0.0) && (eta2 >= 0.0)) )
1418 {
1419 return deltaEta = fabs(eta1 - eta2);
1420 }
1421
1422 else if ( ((eta1 >= 0.0) && (eta2 <= 0.0)) || ((eta1 <= 0.0) && (eta2 >= 0.0)) )
1423 {
1424 return deltaEta = fabs(eta1) + fabs(eta2);
1425 }
1426 else
1427 return 0;
1428 }
1429
1430 float
1431 RecoFirst::getOppositeLength (float a, float b, float theta)
1432 {
1433 // Using the cosine rule we can find the length of one side of a triangle
1434 // c = sqrt(a*a + b*b - 2*a*b*cos(theta))
1435 // where
1436 // a = IP To ECAL Hit Length
1437 // b = IP to Primary Vertex length
1438 // c = Primary Vertex To Hit Lenght
1439 // theta = angle between ECAL hit, IP and Primary vertex
1440 if(Debug2){cout << "a: " << a << ", b: " << b << ", theta: " << theta << endl;}
1441 if(Debug2){cout << "(a*a + b*b - 2*a*b*cos(theta): " << (a*a + b*b - 2*a*b*cos(theta)) << endl;}
1442 float parameter = (a*a + b*b - 2*a*b*cos(theta)) ;
1443 // Check for sqrt of a negative value
1444 if (parameter < 0)
1445 {
1446 if(Debug2)
1447 {
1448 cout << "Can't take sqrt of " << parameter << ")" << endl;
1449 cout << "a: " << a << ", b: " << b << ", theta: " << theta << endl;
1450 }
1451 return 0.0;
1452 }
1453 else
1454 {
1455 float c = sqrt(a*a + b*b - 2*a*b*cos(theta));
1456 if(Debug2){cout << "c: " << c << endl;}
1457 return c;
1458 }
1459 }
1460
1461 float
1462 RecoFirst::findIncludedAngleBetweenHits(float displacedVertex, myParticle firstDaughterRECO, myParticle secondDaughterRECO)
1463 {
1464 // For both electrons get the internal angle between the DisplacedVertexLength_ and the (TimedDistanceToHit - DisplacedVertexLength_)
1465 // We now know 3 sides of a triangle - the DistanceFromPrimaryVertexToHit, the DisplacedVertexLength_, and the (TimedDistanceToHit - DisplacedVertexLength_)
1466 // Using the cosine rule we can find the internal angles.
1467 if (Debug2) {cout << "firsttimedDistanceToHit[medium] : " << firstDaughterRECO.timedDistanceToHit[medium] << endl;}
1468 if (Debug2) {cout << "secondtimedDistanceToHit[medium] : " << secondDaughterRECO.timedDistanceToHit[medium] << endl;}
1469
1470 float AngleBetweenHits;
1471
1472 float firstAlpha = getAngle(displacedVertex, firstDaughterRECO.flightLength[medium], firstDaughterRECO.PrimaryVertexToHit);
1473 if (Debug2) {cout << "firstAlpha: " << firstAlpha << ", displacedVertex: " << displacedVertex << ", firstDaughterRECO.flightLength[medium] : " << firstDaughterRECO.flightLength[medium] << ", firstDaughterRECO.PrimaryVertexToHit: " << firstDaughterRECO.PrimaryVertexToHit << endl;}
1474
1475 float secondAlpha = getAngle(displacedVertex, secondDaughterRECO.flightLength[medium], secondDaughterRECO.PrimaryVertexToHit);
1476 if (Debug2) {cout << "secondAlpha: " << secondAlpha << ", displacedVertex: " << displacedVertex << ", secondDaughterRECO.flightLength[medium] : " << secondDaughterRECO.flightLength[medium] << ", secondDaughterRECO.PrimaryVertexToHit: " << secondDaughterRECO.PrimaryVertexToHit << endl;}
1477
1478 if ((firstAlpha + secondAlpha) > pi)
1479 {
1480 // The total included angle between the two decay paths = (2 * pi - Alpha0 - Alpha1)
1481 AngleBetweenHits = (2.0 * pi) - firstAlpha - secondAlpha;
1482 if (Debug2) {cout << "firstAlpha: " << firstAlpha << ", secondAlpha: " << secondAlpha << ", AngleBetweenHits: " << AngleBetweenHits << endl;}
1483 }
1484 else
1485 {
1486 AngleBetweenHits = firstAlpha + secondAlpha;
1487 }
1488 return AngleBetweenHits;
1489 }
1490
1491 float
1492 RecoFirst::getAngle (float a, float b, float c)
1493 {
1494 // Using the cosine rule we can find the internal angle, alpha.
1495 // Alpha = arc-cos(a*a + b*b - c*c)/2*a*b
1496 // where
1497 // a = DisplacedVertexLength
1498 // c = DistanceFromPrimaryVertexToHit
1499 // b = timedDistanceToHit[medium] - DisplacedVertexLength
1500 if(Debug2){cout << "a: " << a << ", b: " << b << ", c: " << c << endl;}
1501 if(Debug2){cout << "(a*a + b*b - c*c)/(2*a*b): " << (a*a + b*b - c*c)/(2*a*b) << endl;}
1502 float parameter = (a*a + b*b - c*c)/(2*a*b);
1503 // Check for bad parameters for acos() i.e. > 1 or < -1
1504 float Alpha = 0.0;
1505 if (parameter > 1)
1506 {
1507 Alpha = acos(1.0);
1508 if(Debug2)
1509 {
1510 cout << "Bad angle: Acos(" << parameter << ")" << endl;
1511 cout << "a: " << a << ", b: " << b << ", c: " << c << endl;
1512 cout << "Angle: " << Alpha << endl;
1513 }
1514 }
1515 if (parameter < -1)
1516 {
1517 Alpha = acos(-1.0);
1518 if(Debug2)
1519 {
1520 cout << "Bad angle: Acos(" << parameter << ")" << endl;
1521 cout << "a: " << a << ", b: " << b << ", c: " << c << endl;
1522 cout << "Angle: " << Alpha << endl;
1523 }
1524 }
1525 else
1526 {
1527 Alpha = acos(parameter);
1528 if(Debug2){cout << "Angle: " << Alpha << endl;}
1529 }
1530 return Alpha;
1531 }
1532
1533 // The angle between the firstDaughterRECO particle's ECAL hit, the IP and the secondDaughterRECO particle's ECAL hit
1534 float
1535 RecoFirst::getInitialAngleBetweenLeptons(myParticle &firstDaughterRECO, myParticle &secondDaughterRECO)
1536 { TVector3 x1;
1537 TVector3 x0;
1538 if(Debug2){cout << "firstDaughterRECO.endPoint.x(): " << firstDaughterRECO.endPoint.x() << endl;}
1539 if(Debug2){cout << "secondDaughterRECO.endPoint.x(): " << secondDaughterRECO.endPoint.x() << endl;}
1540 if(Debug2){cout << "firstDaughterRECO.endPoint.y(): " << firstDaughterRECO.endPoint.y() << endl;}
1541 if(Debug2){cout << "secondDaughterRECO.endPoint.y(): " << secondDaughterRECO.endPoint.y() << endl;}
1542 if(Debug2){cout << "firstDaughterRECO.endPoint.z(): " << firstDaughterRECO.endPoint.z() << endl;}
1543 if(Debug2){cout << "secondDaughterRECO.endPoint.z(): " << secondDaughterRECO.endPoint.z() << endl;}
1544
1545 x0.SetXYZ(firstDaughterRECO.endPoint.x(), firstDaughterRECO.endPoint.y(), firstDaughterRECO.endPoint.z() );
1546 x1.SetXYZ(secondDaughterRECO.endPoint.x(), secondDaughterRECO.endPoint.y(), secondDaughterRECO.endPoint.z() );
1547 if (Debug2) {cout << "Initial angle between hits: " << x0.Angle(x1) << endl;}
1548 return x0.Angle(x1);
1549 }
1550
1551 // ------------ method called once each job just before starting event loop ------------
1552 void
1553 RecoFirst::beginJob()
1554 {
1555 }
1556
1557 void
1558 RecoFirst::book(Service<TFileService>& fs)
1559 {
1560 if (Zee)
1561 {
1562 hists_["t1"] = fs->make<TH1F> ("Z->ee Ecal Timing Reconstructed Mass", "Reconstructed Mass (GeV)", 100, dummy, 200);
1563 hists_["t1"]->GetXaxis()->SetTitle("Reconstructed Mass (GeV)");
1564
1565 hists_["t2"] = fs->make<TH1F> ("Z->ee Calculated Flight Length (cm)", "Calculated Flight Length (cm)", 100, -5, 200);
1566 hists_["t2"]->GetXaxis()->SetTitle("Calculated Flight Length (cm)");
1567
1568 hists_["t3"] = fs->make<TH1F> ("MC (true) Flight Length (cm)", "MC (true) Flight Length (cm)", 100, dummy, 200);
1569 hists_["t3"]->GetXaxis()->SetTitle("MC (true) Flight Length (cm)");
1570
1571 hists_["t4"] = fs->make<TH2F> ("Z->ee MC (true) vs Calculated Flight Length (cm)", "MC (true) vs Calculated Flight Length (cm)", 100, 0, 200, 100, 0, 200);
1572 hists_["t4"]->GetXaxis()->SetTitle("MC (true) Flight Length (cm)");
1573 hists_["t4"]->GetYaxis()->SetTitle("Calculated Flight Length (cm)");
1574
1575 hists_["t5"] = fs->make<TH2F> ("Z->ee Reconstructed Mass Vs Calculated Flight Length", "Reconstructed Mass (GeV) vs Calculated Flight Length (cm)", 100, 0, 2000, 100, 0, 200);
1576 hists_["t5"]->GetXaxis()->SetTitle("Reconstructed Mass (GeV)");
1577 hists_["t5"]->GetYaxis()->SetTitle("Calculated Flight Length (cm)");
1578
1579 hists_["t6"] = fs->make<TH1F> ("Z->ee MC (true) Mass (GeV)", "MC (true) Mass (GeV)", 100, 0, 2000);
1580 hists_["t6"]->GetXaxis()->SetTitle("True MC Mass (GeV)");
1581
1582 hists_["t7"] = fs->make<TH2F> ("Z->ee Decay Daughter's Hit Time (ns) vs Calculated Flight Length (cm)", "Decay Daughter's Hit Time (ns) vs Calculated Flight Length (cm)", 100, -0.5, 2, 100, 0, 20);
1583 hists_["t7"]->GetXaxis()->SetTitle("Decay Daughter's Hit Time (ns)");
1584 hists_["t7"]->GetYaxis()->SetTitle("Calculated Flight Length (cm)");
1585
1586 hists_["t8"] = fs->make<TH1F> ("Z->ee Measured ECAL Hit Time", "Measured ECAL Hit Time", 100, -4, 3);
1587 hists_["t8"]->GetXaxis()->SetTitle("Measured ECAL Hit Time (ns)");
1588
1589 hists_["t9"] = fs->make<TProfile> ("Z->ee Profile Reconstructed Mass Vs Calculated Flight Length", "Profile Reconstructed Mass (GeV) vs Calculated Flight Length (cm)", 200, 50, 1200, 0, 20);
1590
1591 TGraphAsymmErrors_["t10"] = fs->make<TGraphAsymmErrors> ();
1592
1593 hists_["t11"] = fs->make<TProfile> ("Z->ee Profile Reconstructed Mass Vs True Mass", "Profile Reconstructed Mass (GeV) vs MC Mass - Reconstructed Mass (GeV)", 200, 0, 1200, -50, 50);
1594
1595 hists_["t12"] = fs->make<TH2F> ("Z->ee True MC Mass Vs Reconstructed Mass", "True MC Mass (GeV) vs Reconstructed Mass (GeV)", 100, dummy, 200, 100, dummy, 1000);
1596 hists_["t12"]->GetXaxis()->SetTitle("True MC Mass (GeV)");
1597 hists_["t12"]->GetYaxis()->SetTitle("Reconstructed Mass (GeV)");
1598
1599 hists_["t13"] = fs->make<TH2F> ("Z->ee Reconstructed Flight Length Residual vs Reconstructed Mass Residual", "Reconstructed Flight Length Residual vs Reconstructed Mass Residual", 100, dummy, 20, 100, -300, 300);
1600 hists_["t13"]->GetXaxis()->SetTitle("Reconstructed Flight Length - True MC Flight Length (cm)");
1601 hists_["t13"]->GetYaxis()->SetTitle("Reconstructed Mass - True MC Mass (GeV)");
1602
1603 hists_["t14"] = fs->make<TH1F> ("Z->ee Valid Electron Pair Calculated Flight Length", "Valid Electron Pair Calculated Flight Length", 100, 0, 200);
1604 hists_["t14"]->GetXaxis()->SetTitle("Valid Electron Pair Calculated Flight Length (cm)");
1605
1606 hists_["t15"] = fs->make<TH1F> ("Z->ee Valid Electrons Measured ECAL Hit Time", "Valid Electrons Measured ECAL Hit Time", 100, -0.5, 2);
1607 hists_["t15"]->GetXaxis()->SetTitle("Valid Electron Measured ECAL Hit Time (ns)");
1608
1609 hists_["t16"] = fs->make<TH2F> ("Z->ee True MC Mass vs Reconstructed Mass Residual", "True MC Mass vs Reconstructed Mass Residual", 100, 0, 2000, 100, -1000, 1000);
1610 hists_["t16"]->GetXaxis()->SetTitle("True MC Mass (GeV)");
1611 hists_["t16"]->GetYaxis()->SetTitle("Reconstructed Mass - True MC Mass (GeV)");
1612 }
1613
1614 if (ZPrimeee)
1615 {
1616 hists_["t1"] = fs->make<TH1F> ("Z'->ee Ecal Timing Reconstructed Mass", "Z'->ee Reconstructed Mass (GeV)", 100, dummy, 1400);
1617 hists_["t1"]->GetXaxis()->SetTitle("Reconstructed Mass (GeV)");
1618
1619 hists_["t2"] = fs->make<TH1F> ("Z'->ee Calculated Flight Length (cm)", "Z'->ee Calculated Flight Length (cm)", 100, -5, 20);
1620 hists_["t2"]->GetXaxis()->SetTitle("Calculated Flight Length (cm)");
1621
1622 hists_["t3"] = fs->make<TH1F> ("Z'->ee MC (true) Flight Length (cm)", "Z'->ee MC (true) Flight Length (cm)", 100, dummy, 20);
1623 hists_["t3"]->GetXaxis()->SetTitle("MC (true) Flight Length (cm)");
1624
1625 hists_["t4"] = fs->make<TH2F> ("Z'->ee MC (true) vs Calculated Flight Length (cm)", "Z'->ee MC (true) vs Calculated Flight Length (cm)", 100, 0, 20, 100, 0, 20);
1626 hists_["t4"]->GetXaxis()->SetTitle("MC (true) Flight Length (cm)");
1627 hists_["t4"]->GetYaxis()->SetTitle("Calculated Flight Length (cm)");
1628
1629 hists_["t5"] = fs->make<TH2F> ("Z'->ee Reconstructed Mass Vs Calculated Flight Length", "Z'->ee Reconstructed Mass (GeV) vs Calculated Flight Length (cm)", 100, 0, 1400, 100, 0, 20);
1630 hists_["t5"]->GetXaxis()->SetTitle("Reconstructed Mass (GeV)");
1631 hists_["t5"]->GetYaxis()->SetTitle("Calculated Flight Length (cm)");
1632
1633 hists_["t6"] = fs->make<TH1F> ("Z'->ee MC (true) Mass (GeV)", "Z'->ee MC (true) Mass (GeV)", 100, 0, 1400);
1634 hists_["t6"]->GetXaxis()->SetTitle("True MC Mass (GeV)");
1635
1636 hists_["t7"] = fs->make<TH2F> ("Z'->ee Decay Daughter's Hit Time (ns) vs Calculated Flight Length (cm)", "Z'->ee Decay Daughter's Hit Time (ns) vs Calculated Flight Length (cm)", 100, -0.5, 2, 100, 0, 20);
1637 hists_["t7"]->GetXaxis()->SetTitle("Decay Daughter's Hit Time (ns)");
1638 hists_["t7"]->GetYaxis()->SetTitle("Calculated Flight Length (cm)");
1639
1640 hists_["t8"] = fs->make<TH1F> ("Z'->ee Measured ECAL Hit Time", "Z'->ee Measured ECAL Hit Time", 100, -4, 3);
1641 hists_["t8"]->GetXaxis()->SetTitle("Measured ECAL Hit Time (ns)");
1642
1643 hists_["t9"] = fs->make<TProfile> ("Z'->ee Profile Reconstructed Mass Vs Calculated Flight Length", "Z'->ee Profile Reconstructed Mass (GeV) vs Calculated Flight Length (cm)", 200, 50, 1400, 0, 20);
1644
1645 TGraphAsymmErrors_["t10"] = fs->make<TGraphAsymmErrors> ();
1646
1647 hists_["t11"] = fs->make<TProfile> ("Z'->ee Profile Reconstructed Mass Vs True Mass", "Z'->ee Profile Reconstructed Mass (GeV) vs MC Mass - Reconstructed Mass (GeV)", 200, 0, 1400, -50, 50);
1648
1649 hists_["t12"] = fs->make<TH2F> ("Z'->ee True MC Mass Vs Reconstructed Mass", "Z'->ee True MC Mass (GeV) vs Reconstructed Mass (GeV)", 100, dummy, 1400, 100, dummy, 1400);
1650 hists_["t12"]->GetXaxis()->SetTitle("True MC Mass (GeV)");
1651 hists_["t12"]->GetYaxis()->SetTitle("Reconstructed Mass (GeV)");
1652
1653 hists_["t13"] = fs->make<TH2F> ("Z'->ee Reconstructed Flight Length Residual vs Reconstructed Mass Residual", "Z'->ee Reconstructed Flight Length Residual vs Reconstructed Mass Residual", 100, -5, 20, 100, -300, 300);
1654 hists_["t13"]->GetXaxis()->SetTitle("Reconstructed Flight Length - True MC Flight Length (cm)");
1655 hists_["t13"]->GetYaxis()->SetTitle("Reconstructed Mass - True MC Mass (GeV)");
1656
1657 hists_["t14"] = fs->make<TH1F> ("Z'->ee Valid Electron Pair Calculated Flight Length", "Z'->ee Valid Electron Pair Calculated Flight Length", 100, 0, 20);
1658 hists_["t14"]->GetXaxis()->SetTitle("Valid Electron Pair Calculated Flight Length (cm)");
1659
1660 hists_["t15"] = fs->make<TH1F> ("Z'->ee Valid Electrons Measured ECAL Hit Time", "Z'->ee Valid Electrons Measured ECAL Hit Time", 100, -0.5, 2);
1661 hists_["t15"]->GetXaxis()->SetTitle("Valid Electron Measured ECAL Hit Time (ns)");
1662
1663 hists_["t16"] = fs->make<TH2F> ("Z'->ee True MC Mass vs Reconstructed Mass Residual", "Z'->ee True MC Mass vs Reconstructed Mass Residual", 100, 0, 1400, 100, -400, 400);
1664 hists_["t16"]->GetXaxis()->SetTitle("True MC Mass (GeV)");
1665 hists_["t16"]->GetYaxis()->SetTitle("Reconstructed Mass - True MC Mass (GeV)");
1666 }
1667
1668 if (LLee)
1669 {
1670 hists_["t1"] = fs->make<TH1F> ("LL->ee Ecal Timing Reconstructed Mass", "LL->ee Reconstructed Mass (GeV)", 100, dummy, 1000);
1671 hists_["t1"]->GetXaxis()->SetTitle("Reconstructed Mass (GeV)");
1672
1673 hists_["t2"] = fs->make<TH1F> ("LL->ee Calculated Flight Length (cm)", "LL->ee Calculated Flight Length (cm)", 100, -5, 200);
1674 hists_["t2"]->GetXaxis()->SetTitle("Calculated Flight Length (cm)");
1675
1676 hists_["t3"] = fs->make<TH1F> ("LL->ee MC (true) Flight Length (cm)", "LL->ee MC (true) Flight Length (cm)", 100, dummy, 200);
1677 hists_["t3"]->GetXaxis()->SetTitle("MC (true) Flight Length (cm)");
1678
1679 hists_["t4"] = fs->make<TH2F> ("LL->ee MC (true) vs Calculated Flight Length (cm)", "LL->ee MC (true) vs Calculated Flight Length (cm)", 100, 0, 200, 100, 0, 200);
1680 hists_["t4"]->GetXaxis()->SetTitle("MC (true) Flight Length (cm)");
1681 hists_["t4"]->GetYaxis()->SetTitle("Calculated Flight Length (cm)");
1682
1683 hists_["t5"] = fs->make<TH2F> ("LL->ee Reconstructed Mass Vs Calculated Flight Length", "LL->ee Reconstructed Mass (GeV) vs Calculated Flight Length (cm)", 100, 0, 200, 100, 0, 200);
1684 hists_["t5"]->GetXaxis()->SetTitle("Reconstructed Mass (GeV)");
1685 hists_["t5"]->GetYaxis()->SetTitle("Calculated Flight Length (cm)");
1686
1687 hists_["t6"] = fs->make<TH1F> ("LL->ee MC (true) Mass (GeV)", "LL->ee MC (true) Mass (GeV)", 100, 0, 200);
1688 hists_["t6"]->GetXaxis()->SetTitle("True MC Mass (GeV)");
1689
1690 hists_["t7"] = fs->make<TH2F> ("LL->ee Decay Daughter's Hit Time (ns) vs Calculated Flight Length (cm)", "LL->ee Decay Daughter's Hit Time (ns) vs Calculated Flight Length (cm)", 100, -0.5, 2, 100, 0, 200);
1691 hists_["t7"]->GetXaxis()->SetTitle("Decay Daughter's Hit Time (ns)");
1692 hists_["t7"]->GetYaxis()->SetTitle("Calculated Flight Length (cm)");
1693
1694 hists_["t8"] = fs->make<TH1F> ("LL->ee Measured ECAL Hit Time", "LL->ee Measured ECAL Hit Time", 100, -4, 3);
1695 hists_["t8"]->GetXaxis()->SetTitle("Measured ECAL Hit Time (ns)");
1696
1697 hists_["t9"] = fs->make<TProfile> ("LL->ee Profile Reconstructed Mass Vs Calculated Flight Length", "LL->ee Profile Reconstructed Mass (GeV) vs Calculated Flight Length (cm)", 200, 50, 1200, 0, 200);
1698
1699 TGraphAsymmErrors_["t10"] = fs->make<TGraphAsymmErrors> ();
1700
1701 hists_["t11"] = fs->make<TProfile> ("LL->ee Profile Reconstructed Mass Vs True Mass", "LL->ee Profile Reconstructed Mass (GeV) vs MC Mass - Reconstructed Mass (GeV)", 200, 0, 1200, -50, 50);
1702
1703 hists_["t12"] = fs->make<TH2F> ("LL->ee True MC Mass Vs Reconstructed Mass", "LL->ee True MC Mass (GeV) vs Reconstructed Mass (GeV)", 100, 140, 160, 100, 100, 200);
1704 hists_["t12"]->GetXaxis()->SetTitle("True MC Mass (GeV)");
1705 hists_["t12"]->GetYaxis()->SetTitle("Reconstructed Mass (GeV)");
1706
1707 hists_["t13"] = fs->make<TH2F> ("LL->ee Reconstructed Flight Length Residual vs Reconstructed Mass Residual", "LL->ee Reconstructed Flight Length Residual vs Reconstructed Mass Residual", 100, -150, 200, 100, -300, 1000);
1708 hists_["t13"]->GetXaxis()->SetTitle("Reconstructed Flight Length - True MC Flight Length (cm)");
1709 hists_["t13"]->GetYaxis()->SetTitle("Reconstructed Mass - True MC Mass (GeV)");
1710
1711 hists_["t14"] = fs->make<TH1F> ("LL->ee Valid Electron Pair Calculated Flight Length", "LL->ee Valid Electron Pair Calculated Flight Length", 100, 0, 200);
1712 hists_["t14"]->GetXaxis()->SetTitle("Valid Electron Pair Calculated Flight Length (cm)");
1713
1714 hists_["t15"] = fs->make<TH1F> ("LL->ee Valid Electrons Measured ECAL Hit Time", "LL->ee Valid Electrons Measured ECAL Hit Time", 100, -0.5, 2);
1715 hists_["t15"]->GetXaxis()->SetTitle("Valid Electron Measured ECAL Hit Time (ns)");
1716
1717 hists_["t16"] = fs->make<TH2F> ("LL->ee True MC Mass vs Reconstructed Mass Residual", "LL->ee True MC Mass vs Reconstructed Mass Residual", 100, 140, 160, 100, -50, 50);
1718 hists_["t16"]->GetXaxis()->SetTitle("True MC Mass (GeV)");
1719 hists_["t16"]->GetYaxis()->SetTitle("Reconstructed Mass - True MC Mass (GeV)");
1720
1721 hists_["t17"] = fs->make<TH1F> ("LL->ee Valid Reconstructed Mass (GeV)", "LL->ee Valid Reconstructed Mass (GeV)", 100, 0, 500);
1722 hists_["t17"]->GetXaxis()->SetTitle("Reconstructed Mass (GeV)");
1723
1724 hists_["t18"] = fs->make<TH1F> ("LL->ee Valid Reconstructed Flight Length (cm)", "LL->ee Valid Reconstructed Flight Length (cm)", 100, dummy, 100);
1725 hists_["t18"]->GetXaxis()->SetTitle("Reconstructed Flight Length (cm)");
1726
1727 hists_["t19"] = fs->make<TH2F> ("LL->ee True MC Flight Length (cm) vs Reconstructed Flight Length (cm)", "LL->ee True MC Flight Length (cm) vs Reconstructed Flight Length (cm)", 100, 0, 200, 100, 0, 200);
1728 hists_["t19"]->GetXaxis()->SetTitle("True MC Flight Length (cm)");
1729 hists_["t19"]->GetYaxis()->SetTitle("Reconstructed Flight Length (cm)");
1730
1731 hists_["t20"] = fs->make<TH1F> ("LL->ee Initial Decay Length Estimates (cm)", "LL->ee Initial Decay Length Estimates (cm)", 100, dummy, 500);
1732 hists_["t20"]->GetXaxis()->SetTitle("Initial Decay Length Estimates (cm)");
1733
1734 hists_["t21"] = fs->make<TH1F> ("LL->ee firstDaughterRECO PrimaryVertexToHit (cm)", "LL->ee firstDaughterRECO PrimaryVertexToHit (cm)", 100, dummy, 500);
1735 hists_["t21"]->GetXaxis()->SetTitle("firstDaughterRECO PrimaryVertexToHit (cm)");
1736
1737 hists_["t22"] = fs->make<TH1F> ("LL->ee secondDaughterRECO PrimaryVertexToHit (cm)", "LL->ee secondDaughterRECO PrimaryVertexToHit (cm)", 100, dummy, 500);
1738 hists_["t22"]->GetXaxis()->SetTitle("secondDaughterRECO PrimaryVertexToHit (cm)");
1739
1740 hists_["t23"] = fs->make<TH2F> ("LL->ee Constructed Flight Length (cm) vs Included Angle (rad) vs ", "LL->ee Constructed Flight Length (cm) vs Included Angle (rad)", 100, 0, 20, 100, -pi, pi);
1741 hists_["t23"]->GetXaxis()->SetTitle("Constructed Flight Length (cm)");
1742 hists_["t23"]->GetYaxis()->SetTitle("Included Angle (rad)");
1743
1744 hists_["t24"] = fs->make<TH2F> ("LL->ee True MC Flight Length (cm) vs Constructed Flight Length Residue (cm)", "LL->ee True MC Flight Length (cm) vs Constructed Flight Length Residue (cm)", 100, 0, 200, 100, -200, 20);
1745 hists_["t24"]->GetXaxis()->SetTitle("True MC Flight Length (cm)");
1746 hists_["t24"]->GetYaxis()->SetTitle("Constructed Flight Length Residue (cm)");
1747
1748 hists_["t25"] = fs->make<TH2F> ("LL->ee Calculated Included Angle (rad) vs Valid Reconstructed Mass (GeV)", "Calculated Included Angle (rad) vs Valid Reconstructed Mass (GeV)", 100, -pi, pi, 100, 0, 200);
1749 hists_["t25"]->GetXaxis()->SetTitle("Calculated Included Angle (rad)");
1750 hists_["t25"]->GetYaxis()->SetTitle("Valid Reconstructed Mass (GeV)");
1751
1752 hists_["t26"] = fs->make<TH2F> ("LL->ee ECAL Energy vs Valid Reconstructed Mass (GeV)", "ECAL Energy (GeV) vs Valid Reconstructed Mass (GeV)", 100, 0, 500, 100, 0, 200);
1753 hists_["t26"]->GetXaxis()->SetTitle("sqrt(Energy1 * Energy2) (GeV)");
1754 hists_["t26"]->GetYaxis()->SetTitle("Valid Reconstructed Mass (GeV)");
1755
1756 hists_["t27"] = fs->make<TH2F> ("LL->ee ECAL Energy vs 1 - cos(Included Angle)", "ECAL Energy vs 1 - cos(Included Angle)", 100, 0, 500000, 100, 0, 2);
1757 hists_["t27"]->GetXaxis()->SetTitle("Energy1 * Energy2 (GeV)");
1758 hists_["t27"]->GetYaxis()->SetTitle("1 - cos(Included Angle)");
1759
1760 hists_["t28"] = fs->make<TH2F> ("LL->ee MC (true) included angle vs MC (true) mass (GeV)", "MC (true) included angle vs MC (true) mass (GeV)", 100, 0, pi, 100, 140, 160);
1761 hists_["t28"]->GetXaxis()->SetTitle("MC (true) Included Angle (rad)");
1762 hists_["t28"]->GetYaxis()->SetTitle("MC (true) mass (GeV)");
1763
1764 hists_["t29"] = fs->make<TH2F> ("LL->ee MC (true) included Angle vs Calculated included Angle", "MC (true) included angle vs Calculated included Angle", 100, 0, pi, 100, 0, pi);
1765 hists_["t29"]->GetXaxis()->SetTitle("MC (true) Included Angle (rad)");
1766 hists_["t29"]->GetYaxis()->SetTitle("Calculated included Angle (rad)");
1767
1768 hists_["t30"] = fs->make<TH2F> ("LL->ee MC (true) Flight Length vs MC (true) included Angle", "MC (true) Flight Length vs MC (true) included Angle", 100, 0, 200, 100, 0, pi);
1769 hists_["t30"]->GetXaxis()->SetTitle("MC (true) Flight Length (cm)");
1770 hists_["t30"]->GetYaxis()->SetTitle("MC (true) included Angle (rad)");
1771
1772 hists_["t31"] = fs->make<TH1F> ("LL->ee MC (true) included Angle (rad)", "LL->ee MC (true) included Angle (rad)", 100, 0, pi);
1773 hists_["t31"]->GetXaxis()->SetTitle("MC (true) included Angle (rad)");
1774
1775 hists_["t32"] = fs->make<TH1F> ("LL->ee Calculated included Angle (rad)", "LL->ee Calculated included Angle (rad)", 100, 0, pi);
1776 hists_["t32"]->GetXaxis()->SetTitle("Calculated included Angle (rad)");
1777
1778 hists_["t33"] = fs->make<TH2F> ("LL->ee MC (true) ECAL Hit Time vs Measured Hit Time (ns)", "MC (true) ECAL Hit Time vs Measured Hit Time (ns)", 100, 0, 10, 100, -2, 2);
1779 hists_["t33"]->GetXaxis()->SetTitle("MC (true) Calculated ECAL Hit Time (ns)");
1780 hists_["t33"]->GetYaxis()->SetTitle("Measured ECAL Hit Time (ns)");
1781
1782 hists_["t34"] = fs->make<TH2F> ("LL->ee MC (true) Absolute ECAL Hit Time vs Absolute Measured Hit Time (ns)", "MC (true) Absolute ECAL Hit Time vs Absolute Measured Hit Time (ns)", 100, 0, 20, 100, 0, 20);
1783 hists_["t34"]->GetXaxis()->SetTitle("MC (true) Calculated Absolute ECAL Hit Time (ns)");
1784 hists_["t34"]->GetYaxis()->SetTitle("Measured Absolute ECAL Hit Time (ns)");
1785
1786 hists_["t35"] = fs->make<TH1F> ("LL->ee MC LL Flight Time (ns)", "LL->ee MC LL Flight Time (ns)", 100, 0, 20);
1787 hists_["t32"]->GetXaxis()->SetTitle("MC LL Flight Time (ns)");
1788
1789 hists_["t36"] = fs->make<TH1F> ("LL->ee MC Electron Flight Time (ns)", "LL->ee MC Electron Flight Time (ns)", 100, 0, 20);
1790 hists_["t36"]->GetXaxis()->SetTitle("MC Electron Flight Time (ns)");
1791
1792 hists_["t37"] = fs->make<TH1F> ("LL->ee MC relatavistic Flight Time (ns)", "LL->ee MC relatavistic Flight Time (ns)", 100, 0, 20);
1793 hists_["t37"]->GetXaxis()->SetTitle("MC relatavistic Flight Time (ns)");
1794
1795 }
1796 }
1797
1798 // ------------ method called once each job just after ending the event loop ------------
1799 void
1800 RecoFirst::endJob()
1801 {
1802 Service<TFileService> fs;
1803 if (!fs)
1804 { throw Exception(errors::Configuration, "TFile Service is not registered in cfg file");
1805 }
1806 TGraphAsymmErrors_["t10"] = fs->make<TGraphAsymmErrors> ( n, bestMass, bestFlightLength, lowMass, lowFlightLength, highMass, highFlightLength);
1807 TGraphAsymmErrors_["t10"]->SetTitle("Reconstructed Mass (GeV) vs Calculated Flight Length (cm)");
1808 TGraphAsymmErrors_["t10"]->GetXaxis()->SetTitle("Reconstructed Mass (GeV)");
1809 TGraphAsymmErrors_["t10"]->GetYaxis()->SetTitle("Calculated Flight Length (cm)");
1810
1811 if (Debug2)
1812 {
1813 cout << endl << endl << "Number of electrons: " << numberOfElectrons << endl;
1814 cout << "Number of photons: " << numberOfPhotons << endl;
1815 cout << "Number of number Of Daughters: " << numberOfDaughters << endl;
1816 cout << "Number of electron/photon pairs: " << numberOfElectronPhotonPairs << endl;
1817 cout << "Number of ECAL hits of energy < "<< crystalMinEnergy << " GeV: " << lowCrystalHitEnergy << endl;
1818 cout << "Number of negative hit times: " << negativeHitTime << endl;
1819 cout << "Number of Zs without two positive times: " << numberOfZsWithoutTwoPositiveTimes << endl;
1820 cout << "Number of Zs with a displaced vertex: " << numberOfDisplacedVertices << endl;
1821 cout << "Number of Zs without a displaced vertex convergence: " << noDisplacedVertexConvergence << endl;
1822 cout << "Number of Zs with a negative decay length: " << nonPhysicalDecayLength << endl;
1823 cout << "Number of Zs mass reconstructions: " << massReconstructions << endl;
1824 cout << "Number of validations: " << countValidations << endl;
1825 cout << "Number of validated reconstructions where both RECO & MC electrons are close : " << ValidatedReconstructions << endl;
1826 cout << "Number of close electrons with negative hit time : " << closeElectronsWithNegativeHitTime << endl;
1827 cout << "Number of negative flight lengths : " << negativeFlightLength << endl;
1828 cout << endl;
1829
1830 cout << "Number of events with a primary vertex: " << numberOfPrimaryVertexEvents << endl;
1831 cout << "Number of validation events: " << ValidatedEvents << endl;
1832 cout << "Number of events with no particles: " << noParticles << endl;
1833 cout << "Number of Z particles: " << numberOfZParticles << endl;
1834 cout << "Number of events with Z above minimum mass of " << minimumZMass << ": " << numberOfZeventsAboveMinimumMass << endl;
1835 cout << "Number of events with minimum mass Z & 2 MC daughters: " << numberOfZeventsWithTwoMcDaughters << endl;
1836 cout << "Number of events with MC daughter not in final state: " << numberMcDaughterElectronsNotFinalState << endl;
1837 cout << "Number of Z decays with badRecoDeltaRMatch: " << badRecoDeltaRMatch << endl;
1838 cout << "Number of Z decays with goodRecoElectron: " << goodRecoElectron << endl;
1839 cout << "Number of Z decays with goodRecoPhoton: " << goodRecoPhoton << endl;
1840 cout << "Number of Z decays with noRecoMatch: " << noRecoMatch << endl;
1841 cout << "Number of leptons with nullSuperClusters: " << nullSuperClusters << endl;
1842 cout << "Number of leptons with zero energy: " << zeroEnergyLepton << endl;
1843 cout << "Number of Z events & found MC daughters: " << foundDaughters << endl;
1844 cout << "Number of Z decays with matched RECO daughters: " << zDecaysWithEnergeticDaughters << endl;
1845 cout << "Number of Zs with two RECO daughters: " << zWithTwoRecoDaughters << endl;
1846 cout << "Number of Zs entering veto: " << recoPairsGoingIntoVeto << endl;
1847 cout << "Number of Zs failing isolation: " << failedIsolation << endl;
1848 cout << "Number of Zs failing barrel-endcap gap: " << failedBarrelEndcapGap << endl;
1849 cout << "Number of Zs failing eta cut: " << failedEtaCut << endl;
1850 cout << "Number of Zs failing minimum Et cut: " << failedMinEt << endl;
1851 cout << "Number of Zs passing veto: " << recoPairsPassedVeto << endl;
1852 cout << "Number of reconstructions where electrons are too close: " << minimumAngleBetweenElectronsRejects << endl;
1853 cout << "Number of Zs with middle reconstructed mass: " << middleReconstructedMass << endl;
1854 cout << "Number of Zs reconstructed mass plotted: " << massCalcCounter << endl;
1855 cout << "Number of electron decays: " << ElectronDecays << endl;
1856 cout << "Number of photon decays: " << PhotonDecays << endl;
1857 cout << "Number of brem electrons: " << bremElectrons << endl;
1858 cout << "Number of muon decays: " << MuonDecays << endl;
1859 cout << "Number of tau decays: " << TauDecays << endl;
1860 }
1861 }
1862
1863 // ------------ method called when starting to processes a run ------------
1864 void
1865 RecoFirst::beginRun(edm::Run const&, edm::EventSetup const&)
1866 {
1867 Service<TFileService> fs;
1868 if (!fs)
1869 { throw Exception(errors::Configuration, "TFile Service is not registered in cfg file");
1870 }
1871
1872 // book histogram
1873 book (fs);
1874 }
1875
1876 // ------------ method called when ending the processing of a run ------------
1877 void
1878 RecoFirst::endRun(edm::Run const&, edm::EventSetup const&)
1879 {
1880 }
1881
1882 // ------------ method called when starting to processes a luminosity block ------------
1883 void
1884 RecoFirst::beginLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&)
1885 {
1886 }
1887
1888 // ------------ method called when ending the processing of a luminosity block ------------
1889 void
1890 RecoFirst::endLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&)
1891 {
1892 }
1893
1894 // ------------ method fills 'descriptions' with the allowed parameters for the module ------------
1895 void
1896 RecoFirst::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
1897 //The following says we do not know what parameters are allowed so do no validation
1898 // Please change this to state exactly what you do use, even if it is no parameters
1899 edm::ParameterSetDescription desc;
1900 desc.setUnknown();
1901 descriptions.addDefault(desc);
1902 }
1903
1904 //define this as a plug-in
1905 DEFINE_FWK_MODULE(RecoFirst);