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