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

# User Rev Content
1 tonypoll 1.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);