9 #include <EVENT/LCCollection.h>
10 #include <EVENT/MCParticle.h>
11 #include <IMPL/LCCollectionVec.h>
14 #include <marlin/VerbosityLevels.h>
18 #include <TLorentzVector.h>
20 using namespace lcio ;
21 using namespace marlin ;
26 : Processor(
"IsolatedLeptonFinderProcessor") {
29 _description =
"Isolated Lepton Finder Processor" ;
32 registerInputCollection( LCIO::RECONSTRUCTEDPARTICLE,
34 "Input collection of ReconstructedParticles",
36 std::string(
"PandoraPFOs"));
38 registerOutputCollection( LCIO::RECONSTRUCTEDPARTICLE,
39 "OutputCollectionWithoutIsolatedLepton",
40 "Copy of input collection but without the isolated leptons",
42 std::string(
"PandoraPFOsWithoutIsoLep") );
44 registerOutputCollection( LCIO::RECONSTRUCTEDPARTICLE,
45 "OutputCollectionIsolatedLeptons",
46 "Output collection of isolated leptons",
48 std::string(
"Isolep") );
50 registerProcessorParameter(
"CosConeAngle",
51 "Cosine of the half-angle of the cone used in isolation criteria",
55 registerProcessorParameter(
"UsePID",
56 "Use primitive particle ID based on calorimeter energy deposits",
60 registerProcessorParameter(
"ElectronMinEnergyDepositByMomentum",
61 "Electron ID: Minimum energy deposit divided by momentum",
65 registerProcessorParameter(
"ElectronMaxEnergyDepositByMomentum",
66 "Electron ID: Maximum energy deposit divided by momentum",
70 registerProcessorParameter(
"ElectronMinEcalToHcalFraction",
71 "Electron ID: Minimum Ecal deposit divided by sum of Ecal and Hcal deposits",
75 registerProcessorParameter(
"ElectronMaxEcalToHcalFraction",
76 "Electron ID: Maximum Ecal deposit divided by sum of Ecal and Hcal deposits",
80 registerProcessorParameter(
"MuonMinEnergyDepositByMomentum",
81 "Muon ID: Minimum energy deposit divided by momentum",
85 registerProcessorParameter(
"MuonMaxEnergyDepositByMomentum",
86 "Muon ID: Maximum energy deposit divided by momentum",
90 registerProcessorParameter(
"MuonMinEcalToHcalFraction",
91 "Muon ID: Minimum Ecal deposit divided by sum of Ecal and Hcal deposits",
95 registerProcessorParameter(
"MuonMaxEcalToHcalFraction",
96 "Muon ID: Maximum Ecal deposit divided by sum of Ecal and Hcal deposits",
100 registerProcessorParameter(
"UseImpactParameter",
101 "Use impact parameter cuts for consistency with primary/secondary track",
105 registerProcessorParameter(
"ImpactParameterMinD0",
106 "Minimum d0 impact parameter",
110 registerProcessorParameter(
"ImpactParameterMaxD0",
111 "Maximum d0 impact parameter",
115 registerProcessorParameter(
"ImpactParameterMinZ0",
116 "Minimum z0 impact parameter",
120 registerProcessorParameter(
"ImpactParameterMaxZ0",
121 "Maximum z0 impact parameter",
125 registerProcessorParameter(
"ImpactParameterMin3D",
126 "Minimum impact parameter in 3D",
130 registerProcessorParameter(
"ImpactParameterMax3D",
131 "Maximum impact parameter in 3D",
135 registerProcessorParameter(
"UseImpactParameterSignificance",
136 "Use impact parameter significance cuts for consistency with primary/secondary track",
140 registerProcessorParameter(
"ImpactParameterMinD0Significance",
141 "Minimum d0 impact parameter significance",
145 registerProcessorParameter(
"ImpactParameterMaxD0Significance",
146 "Maximum d0 impact parameter significance",
150 registerProcessorParameter(
"ImpactParameterMinZ0Significance",
151 "Minimum z0 impact parameter significance",
155 registerProcessorParameter(
"ImpactParameterMaxZ0Significance",
156 "Maximum z0 impact parameter significance",
160 registerProcessorParameter(
"ImpactParameterMin3DSignificance",
161 "Minimum impact parameter significance in 3D",
165 registerProcessorParameter(
"ImpactParameterMax3DSignificance",
166 "Maximum impact parameter significance in 3D",
170 registerProcessorParameter(
"UseRectangularIsolation",
171 "Use rectangular cuts on track and cone energy",
175 registerProcessorParameter(
"IsolationMinimumTrackEnergy",
176 "Minimum track energy for isolation requirement",
180 registerProcessorParameter(
"IsolationMaximumTrackEnergy",
181 "Maximum track energy for isolation requirement",
185 registerProcessorParameter(
"IsolationMinimumConeEnergy",
186 "Minimum cone energy for isolation requirement",
190 registerProcessorParameter(
"IsolationMaximumConeEnergy",
191 "Maximum cone energy for isolation requirement",
195 registerProcessorParameter(
"UsePolynomialIsolation",
196 "Use polynomial cuts on track and cone energy",
200 registerProcessorParameter(
"IsolationPolynomialCutA",
201 "Polynomial cut (A) on track energy and cone energy: Econe^2 < A*Etrk^2+B*Etrk+C",
205 registerProcessorParameter(
"IsolationPolynomialCutB",
206 "Polynomial cut (B) on track energy and cone energy: Econe^2 < A*Etrk^2+B*Etrk+C",
210 registerProcessorParameter(
"IsolationPolynomialCutC",
211 "Polynomial cut (C) on track energy and cone energy: Econe^2 < A*Etrk^2+B*Etrk+C",
215 registerProcessorParameter(
"UseJetIsolation",
216 "Use jet-based isolation",
220 registerInputCollection( LCIO::RECONSTRUCTEDPARTICLE,
222 "Input collection of jets for isolation",
224 std::string(
"JetsForIsolation"));
226 registerProcessorParameter(
"JetIsolationVetoMinimumXt",
227 "Minimum Xt in jet-based isolation",
231 registerProcessorParameter(
"JetIsolationVetoMaximumXt",
232 "Maximum Xt in jet-based isolation",
236 registerProcessorParameter(
"JetIsolationVetoMinimumZ",
237 "Mininum Z in jet-based isolation",
241 registerProcessorParameter(
"JetIsolationVetoMaximumZ",
242 "Maximum Z in jet-based isolation",
246 registerProcessorParameter(
"UseDressedLeptons",
247 "Dress leptons with close-by particles",
251 registerProcessorParameter(
"MergeCloseElectrons",
252 "Merge close-by electrons into higher energy lepton",
256 registerProcessorParameter(
"DressPhotonConeAngle",
257 "Half-angle (in degrees) of the cone used for lepton dressing with photons",
261 registerProcessorParameter(
"MergeLeptonConeAngle",
262 "Half-angle (in degrees) of the cone used for lepton merging",
266 registerProcessorParameter(
"UsePandoraIDs",
267 "Use Pandora particle IDs for algorithm",
274 streamlog_out(DEBUG) <<
" init called " << std::endl ;
280 streamlog_out(DEBUG) <<std::endl;
281 streamlog_out(DEBUG) <<
"processing event: " << evt->getEventNumber() <<
" in run: " << evt->getRunNumber() << std::endl ;
289 auto outIsoLepCol = std::unique_ptr<LCCollectionVec>(
new LCCollectionVec( LCIO::RECONSTRUCTEDPARTICLE ) );
291 auto outPFOsRemovedIsoLepCol = std::unique_ptr<LCCollectionVec>(
new LCCollectionVec( LCIO::RECONSTRUCTEDPARTICLE ) );
296 int njet = colJet->getNumberOfElements();
297 for (
int i=0; i<njet; ++i) {
298 ReconstructedParticle* jet =
static_cast<ReconstructedParticle*
>( colJet->getElementAt(i) );
299 for (ReconstructedParticleVec::const_iterator iter = jet->getParticles().begin();
300 iter != jet->getParticles().end(); ++iter) {
301 _rpJetMap.insert( std::make_pair( *iter, jet ) );
307 std::vector<int> goodLeptonIndices;
308 int npfo =
_pfoCol->getNumberOfElements();
309 for (
int i = 0; i < npfo; i++ ) {
310 ReconstructedParticle* pfo =
static_cast<ReconstructedParticle*
>(
_pfoCol->getElementAt(i) );
319 if (
IsLepton( pfo )) goodLeptonIndices.push_back(i);
321 goodLeptonIndices.push_back(i);
326 std::sort(goodLeptonIndices.begin(), goodLeptonIndices.end(), [
this](
const int i,
const int j) {
return isMoreEnergetic(i, j);});
329 for (
unsigned int i = 0; i < goodLeptonIndices.size(); ++i)
331 ReconstructedParticle* pfo_tmp =
static_cast<ReconstructedParticle*
>(
_pfoCol->getElementAt(goodLeptonIndices.at(i) ));
340 double energy_before = pfo->getEnergy();
345 streamlog_out(DEBUG) <<
"dress lepton " << i <<
" with " << n_working_list_before -
_workingList.size() <<
" particles: energy " << energy_before <<
" -> " << pfo->getEnergy() << std::endl ;
350 outIsoLepCol->addElement( pfo );
352 outPFOsRemovedIsoLepCol->addElement( pfo );
357 for (
unsigned int i = 0; i <
_workingList.size(); i++ ) {
359 if (std::find(goodLeptonIndices.begin(), goodLeptonIndices.end(), i) != goodLeptonIndices.end()){
362 ReconstructedParticle* pfo_tmp =
static_cast<ReconstructedParticle*
>(
_workingList.at(i) );
364 outPFOsRemovedIsoLepCol->addElement( pfo );
372 TVector3 P_lep( pfo->getMomentum() );
373 int npfo =
_pfoCol->getNumberOfElements();
374 std::vector<int> _dressedPFOs {};
375 for (
int i = 0; i < npfo; i++ ) {
376 ReconstructedParticle* pfo_dress =
static_cast<ReconstructedParticle*
>(
_pfoCol->getElementAt(i) );
379 bool isPhoton =
IsPhoton(pfo_dress);
380 bool isElectron = !isPhoton &&
IsElectron(pfo_dress);
381 if (!isPhoton && !isElectron)
continue;
386 if ( i == PFO_idx )
continue;
388 TVector3 Pdress( pfo_dress->getMomentum() );
389 float theta = TMath::ACos(P_lep.Dot( Pdress )/(P_lep.Mag()*Pdress.Mag())) * 360 / (2 * TMath::Pi());
393 if (std::find(_dressedPFOs.begin(), _dressedPFOs.end(), i) != _dressedPFOs.end()){
394 if (isPhoton) {streamlog_out(DEBUG) <<
"WARNING: photon "<<i<<
" with theta "<<theta <<
" and type "<<pfo->getType()<<
" already close to another lepton!"<<std::endl;}
395 else if (isElectron) {streamlog_out(DEBUG) <<
"WARNING: lepton "<<i<<
" with theta "<<theta <<
" and type "<<pfo->getType()<<
" already close to another lepton!"<<std::endl;}
399 if (isPhoton) {streamlog_out(DEBUG) <<
"MESSAGE: dressing photon "<<i<<
" with theta "<<theta <<
" and type "<<pfo->getType()<<std::endl;}
400 else if (isElectron) {streamlog_out(DEBUG) <<
"MESSAGE: merging lepton "<<i<<
" with theta "<<theta <<
" and type "<<pfo->getType()<<std::endl;}
401 _dressedPFOs.push_back(i);
403 double dressedMomentum[3] = {pfo->getMomentum()[0] + pfo_dress->getMomentum()[0],
404 pfo->getMomentum()[1] + pfo_dress->getMomentum()[1],
405 pfo->getMomentum()[2] + pfo_dress->getMomentum()[2]};
406 double dressedE = pfo->getEnergy() + pfo_dress->getEnergy();
407 pfo->setMomentum(dressedMomentum);
408 pfo->setEnergy(dressedE);
416 ReconstructedParticleImpl* pfo =
new ReconstructedParticleImpl();
417 pfo->setMomentum(pfo_orig->getMomentum());
418 pfo->setEnergy(pfo_orig->getEnergy());
419 pfo->setType(pfo_orig->getType());
420 pfo->setCovMatrix(pfo_orig->getCovMatrix());
421 pfo->setMass(pfo_orig->getMass());
422 pfo->setCharge(pfo_orig->getCharge());
423 pfo->setParticleIDUsed(pfo_orig->getParticleIDUsed());
424 pfo->setGoodnessOfPID(pfo_orig->getGoodnessOfPID());
425 pfo->setStartVertex(pfo_orig->getStartVertex());
426 for(
unsigned int i=0;i<pfo->getTracks().size();i++){
427 pfo->addTrack(pfo_orig->getTracks()[i]);
429 for(
unsigned int i=0;i<pfo->getClusters().size();i++){
430 pfo->addCluster(pfo_orig->getClusters()[i]);
435 if ( pfo->getCharge() == 0 )
return false;
440 if ( pfo->getType() == 22 )
return true;
449 double ecale = CalE[0];
450 double hcale = CalE[1];
451 double p = TVector3( pfo->getMomentum() ).Mag();
452 double calByP = p>0 ? (ecale + hcale)/p : 0;
453 double calSum = ecale+hcale;
454 double ecalFrac = calSum>0 ? ecale / calSum : 0;
470 double ecale = CalE[0];
471 double hcale = CalE[1];
472 double p = TVector3( pfo->getMomentum() ).Mag();
473 double calByP = p>0 ? (ecale + hcale)/p : 0;
474 double calSum = ecale+hcale;
475 double ecalFrac = calSum>0 ? ecale / calSum : 0;
524 float E = pfo->getEnergy() ;
536 float E = pfo->getEnergy() ;
552 ReconstructedParticle* jet =
_rpJetMap[pfo];
553 TVector3 vec1( pfo->getMomentum() );
554 TVector3 jetmom( jet->getMomentum() );
555 TLorentzVector jetmom4( jet->getMomentum(), jet->getEnergy() );
557 float jetxt = vec1.Pt( jetmom )/jetmom4.M();
558 float jetz = pfo->getEnergy()/jet->getEnergy();
571 const EVENT::TrackVec & trkvec = pfo->getTracks();
573 if (trkvec.size()==0)
return false;
576 float d0 = fabs(trkvec[0]->getD0());
577 float z0 = fabs(trkvec[0]->getZ0());
578 float r0 = sqrt( d0*d0 + z0*z0 );
580 if ( d0 <
_minD0 )
return false;
581 if ( d0 >
_maxD0 )
return false;
582 if ( z0 <
_minZ0 )
return false;
583 if ( z0 >
_maxZ0 )
return false;
584 if ( r0 <
_minR0 )
return false;
585 if ( r0 >
_maxR0 )
return false;
591 const EVENT::TrackVec & trkvec = pfo->getTracks();
593 if (trkvec.size()==0)
return false;
596 float d0 = fabs(trkvec[0]->getD0());
597 float z0 = fabs(trkvec[0]->getZ0());
598 float d0err = sqrt(trkvec[0]->getCovMatrix()[0]);
599 float z0err = sqrt(trkvec[0]->getCovMatrix()[9]);
601 float d0sig = d0err != 0 ? d0/d0err : 0;
602 float z0sig = z0err != 0 ? z0/z0err : 0;
603 float r0sig = sqrt( d0sig*d0sig + z0sig*z0sig );
618 TVector3 P( pfo->getMomentum() );
620 for (
int i = 0; i < npfo; i++ ) {
621 ReconstructedParticle* pfo_i =
static_cast<ReconstructedParticle*
>(
_workingList.at(i) );
624 if ( pfo == pfo_i )
continue;
626 TVector3 P_i( pfo_i->getMomentum() );
627 float cosTheta = P.Dot( P_i )/(P.Mag()*P_i.Mag());
629 coneE += pfo_i->getEnergy();
638 std::vector<lcio::Cluster*> clusters = pfo->getClusters();
639 for ( std::vector<lcio::Cluster*>::const_iterator iCluster=clusters.begin();
640 iCluster!=clusters.end();
642 ecal += (*iCluster)->getSubdetectorEnergies()[0];
643 hcal += (*iCluster)->getSubdetectorEnergies()[1];
std::string _outputIsoLepCollection
Output collection of isolated leptons.
float _muonMaxEnergyDepositByMomentum
bool _useImpactParameterSignificance
If set to true, uses impact parameter significance cuts.
bool IsIsolatedRectangular(ReconstructedParticle *pfo)
Returns true if isolated, as defined by the cone energy.
bool _usePandoraIDs
If set to true, uses Pandora particle IDs.
void dressLepton(ReconstructedParticleImpl *pfo, int PFO_idx)
Adds photons around lepton to four vector.
IsolatedLeptonFinderProcessor()
void getCalEnergy(ReconstructedParticle *pfo, float *cale)
[0]:Ecal energy, [1]:Hcal energy
std::vector< ReconstructedParticle * > _workingList
bool IsLepton(ReconstructedParticle *pfo)
Returns true if it passes muon or electron ID cuts.
float _electronMaxEcalToHcalFraction
float _electronMaxEnergyDepositByMomentum
bool PassesImpactParameterCuts(ReconstructedParticle *pfo)
Returns true if it passes impact parameter cuts.
bool IsGoodLepton(ReconstructedParticle *pfo)
Returns true if pfo is a lepton.
ReconstructedParticleImpl * CopyReconstructedParticle(ReconstructedParticle *pfo)
Replace missing copy constructor by hand.
bool PassesImpactParameterSignificanceCuts(ReconstructedParticle *pfo)
Returns true if it passes impact parameter significance cuts.
bool _mergeCloseElectrons
float _muonMinEcalToHcalFraction
bool IsIsolatedPolynomial(ReconstructedParticle *pfo)
bool IsIsolatedLepton(ReconstructedParticle *pfo)
Returns true if pfo is an isolated lepton.
std::map< ReconstructedParticle *, ReconstructedParticle * > _rpJetMap
IsolatedLeptonFinderProcessor aIsolatedLeptonFinderProcessor
bool _usePolynomialIsolation
If set to true, uses polynomial cuts for isolation.
float _dressPhotonConeAngle
bool _usePID
If set to true, uses PID cuts.
bool IsCharged(ReconstructedParticle *pfo)
Returns true if charged.
bool _useImpactParameter
If set to true, uses impact parameter cuts.
float _muonMinEnergyDepositByMomentum
float _electronMinEcalToHcalFraction
virtual void processEvent(LCEvent *evt)
bool IsPhoton(ReconstructedParticle *pfo)
Returns true if it passes photon ID cuts.
float getConeEnergy(ReconstructedParticle *pfo)
Calculates the cone energy.
bool IsElectron(ReconstructedParticle *pfo)
Returns true if it passes electron ID cuts.
bool _useJetIsolation
If set to true, uses jet-based isolation (LAL algorithm)
bool IsMuon(ReconstructedParticle *pfo)
Returns true if it passes muon ID cuts.
std::vector< LCCollection * > LCCollectionVec
std::string _outputPFOsRemovedIsoLepCollection
Output collection (all input with isolated leptons removed)
float _electronMinEnergyDepositByMomentum
std::string _jetCollectionName
bool _useRectangularIsolation
If set to true, uses rectangular cuts for isolation.
bool _useDressedLeptons
If set to true, uses lepton dressing.
Marlin processor for finding isolated leptons.
bool isMoreEnergetic(int i, int j)
Helper function to order PFOS by energy.
std::string _inputPFOsCollection
Input collection.
bool IsIsolatedJet(ReconstructedParticle *pfo)
float _mergeLeptonConeAngle
float _muonMaxEcalToHcalFraction