All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
TaJetClustering.cc
Go to the documentation of this file.
1 #include <stdlib.h>
2 #include "TaJetClustering.h"
3 #include <iostream>
4 #include <math.h>
5 #include <algorithm>
6 
7 #include <EVENT/LCCollection.h>
8 #include <EVENT/MCParticle.h>
9 #include <EVENT/ReconstructedParticle.h>
10 #include <IMPL/LCCollectionVec.h>
11 #include <IMPL/ReconstructedParticleImpl.h>
12 
13 // ----- include for verbosity dependend logging ---------
14 #include "marlin/VerbosityLevels.h"
15 
16 #include "TVector3.h"
17 
18 
19 // 090128 large change: angle based -> invmass based
20 
21 using namespace lcio ;
22 using namespace marlin ;
23 using namespace std;
24 
26 
27 TaJetClustering::TaJetClustering() : Processor("TaJetClustering")
28 {
29 
30  // modify processor description
31  _description = "Tau Jet Finding" ;
32 
33  // collections
34  registerInputCollection( LCIO::RECONSTRUCTEDPARTICLE,
35  "PFOCollection",
36  "PandoraPFA PFO collection",
38  std::string("PandoraPFOs") );
39 
40  registerOutputCollection( LCIO::RECONSTRUCTEDPARTICLE,
41  "OutputTauCollection",
42  "Tau output collection",
44  std::string("TaJets") );
45 
46  registerOutputCollection( LCIO::RECONSTRUCTEDPARTICLE,
47  "RemainPFOCollection",
48  "Remained PFO collection",
50  std::string("RemainPFOs") );
51 
52  // steering parameters
53  //registerProcessorParameter( "MaxTaus", "Number of maximum taus to be accepted", _maxTaus,100);
54  //registerProcessorParameter( "ReturnCutTaus", "Return cut taus to remain PFO collection", _returnCutTaus,1);
55 
56  // clustering params
57  registerProcessorParameter( "TauMass",
58  "Tau mass for tau clustering [GeV]",
59  _tauMass,
60  2.0 );
61  registerProcessorParameter( "TauCosAngle",
62  "Allowed cosine angle to be clustered",
64  0.98 );
65 
66  // selection switch
67  registerProcessorParameter( "NoSelection",
68  "Neither primary nor cone cut at all if true. Only clustering.",
70  0 );
71  // primary cuts
72  registerProcessorParameter( "MinimumTrackEnergy",
73  "Minimum track energy to be accepted as taus",
75  2.0 );
76  registerProcessorParameter( "MinimumJetEnergy",
77  "Minimum jet energy to be accepted as taus",
79  3.0 );
80  registerProcessorParameter( "MinimumTrackEnergyAssoc",
81  "Minimum track energy to be counted",
83  2.0 );
84  registerProcessorParameter( "MaximumNeutralEnergyIn3Prong",
85  "Reject 3-prong taus if including neutral energy more than this number in GeV",
87  1.0 );
88  registerProcessorParameter( "AcceptFlexibleLowEnergyTrack",
89  "Low energy tracks can be accepted as either charged and neutral if true",
91  1 );
92 
93  // cone cuts
94  registerProcessorParameter( "ConeMinCosAngle",
95  "Minimum cosine angle for cone",
97  0.90 );
98  registerProcessorParameter( "ConeMaxCosAngle",
99  "Maximum cosine angle for cone",
101  1.0 );
102  registerProcessorParameter( "ConeMaxEnergyFrac",
103  "Energy fraction of cone compared to central",
105  0.1 );
106 
107  // following cuts are found not useful now, so commented out for simplicity
108  /*
109  // impact parameter cuts
110  registerProcessorParameter( "IPCutsMinimumTrackEnergy",
111  "Minimum track energy for impact parameter acception",
112  _ipCutsMinimumTrackEnergy,
113  1000.0 );
114  registerProcessorParameter( "IPCutsSigmaOneProng",
115  "Minimum number of sigma for one prong tau tracks",
116  _ipCutsSigmaOneProng,
117  3. );
118  registerProcessorParameter( "IPCutsSigmaThreeProngNoNeutrals",
119  "Minimum number of sigma for three prong tau without neutrals",
120  _ipCutsSigmaThreeProngNoNeutrals,
121  5. );
122  registerProcessorParameter( "IPCutsSigmaThreeProngWithNeutrals",
123  "Minimum number of sigma for three prong tau with neutrals, used with cone cuts (so looser)",
124  _ipCutsSigmaThreeProngWithNeutrals,
125  3. );
126  registerProcessorParameter( "IPMaxAbsolute",
127  "Maximum absolute d0/z0 for tau",
128  _ipMaxAbsolute,
129  1.0 );
130 
131  // lepton ID cuts
132  registerProcessorParameter( "LeptonCutsMinimumTrackEnergy",
133  "Minimum track energy for lepton ID acception",
134  _leptonCutsMinimumTrackEnergy,
135  1000.0 );
136  registerProcessorParameter( "MuMaxFracEcal",
137  "Max ECAL fraction for muon ID",
138  _muMaxFracEcal,
139  0.5 );
140  registerProcessorParameter( "MuMaxCalByTrack",
141  "Max CAL/track energy ratio for muon ID",
142  _muMaxCalByTrack,
143  0.5 );
144  registerProcessorParameter( "EMinFracEcal",
145  "Min ECAL fraction for electron ID",
146  _eMinFracEcal,
147  0.97 );
148  registerProcessorParameter( "EMinCalByTrack",
149  "Min CAL/track energy ratio for electron ID",
150  _eMinCalByTrack,
151  0.9 );
152  registerProcessorParameter( "EMaxCalByTrack",
153  "Max CAL/track energy ratio for electron ID",
154  _eMaxCalByTrack,
155  1.1 );
156  */
157 }
158 
159 
161 
162  streamlog_out(DEBUG) << " init called "
163  << std::endl ;
164 
165  // usually a good idea to
166  printParameters() ;
167 
168  _nRun = 0 ;
169  _nEvt = 0 ;
170 
171 }
172 
173 void TaJetClustering::processRunHeader( LCRunHeader* /*run*/ ) {
174 
175  _nRun++ ;
176 }
177 
178 bool compareEnergy( ReconstructedParticle * const &p1, ReconstructedParticle * const &p2 )
179 {
180  return p1->getEnergy() > p2->getEnergy();
181 }
182 
183 void TaJetClustering::processEvent( LCEvent * evt ) {
184 
185  // obtain Reconstructed Particles
186  LCCollection* col = evt->getCollection(_pfoCollectionName);
187  int nPart = col->getNumberOfElements();
188 
189  // output collection
190  LCCollectionVec* pTaJetsCol= new LCCollectionVec( LCIO::RECONSTRUCTEDPARTICLE );
191  LCCollectionVec* pRemainCol= new LCCollectionVec( LCIO::RECONSTRUCTEDPARTICLE );
192  pRemainCol->setSubset(true);
193 
194  vector< ReconstructedParticle * > parts;
195  vector< ReconstructedParticle * > tajets;
196 
197  for( int i = 0; i < nPart; i++ ) {
198  parts.push_back( dynamic_cast< ReconstructedParticle* >( col->getElementAt(i) ) );
199  }
200 
201  sort( parts.begin(), parts.end(), compareEnergy );
202  /*
203  cout << "PFOs in event #" << _nEvt << endl;
204  for(int i = 0; i < nPart; i++ ){
205  cout << parts[i]->getEnergy() << (parts[i]->getCharge() ? "C" : "N") << endl;
206  }
207  */
208  // Jet finding: around charged particle
209  // because we do not care neutral jets for tau finding
210  //cout << "Tau reconstruction start." << endl;
211  for( int i = 0; i < nPart; i++ )
212  {
213  ReconstructedParticle *pCur = parts[i];
214  if( pCur == NULL ) continue; // already associated particle skipped.
215  if( !pCur->getCharge() ) continue; // neutral particle skipped.
216  if( pCur->getEnergy() < _minimumTrackEnergy ) break;
217 
218  //cout << "Targetting to " << i << "th charged particle: energy = " << pCur->getEnergy() << endl;
219 
220  // create output jet
221  vector< ReconstructedParticle * > jetTracks, jetNeutrals;
222  //pJet->addParticle(pCur);
223  jetTracks.push_back( pCur );
224 
225  double jetEnergy = pCur->getEnergy();
226  TVector3 jetMomentum(pCur->getMomentum());
227  double jetCharge = pCur->getCharge();
228  int ntracks = 1;
229  double eneutral = 0.;
230  /*
231  cout << "Direction: ( " << pCur->getMomentum()[0] << ", " << pCur->getMomentum()[1] << ", "
232  << pCur->getMomentum()[2] << " )" << endl;
233  */
234  int nPartAssoc = 1, nPartAssocPriv = 0;
235 
236  while( nPartAssoc != nPartAssocPriv ){
237  for( int j = 0; j < nPart; j++ )
238  {
239  ReconstructedParticle *pCur2 = parts[j];
240 
241  // remove particles which is already included in the current jet
242  if( pCur2 == NULL ) continue; // already associated particle skipped.
243  if( pCur2->getCharge() && find( jetTracks.begin(), jetTracks.end(), pCur2 ) != jetTracks.end() ) continue;
244  if( !pCur2->getCharge() && find( jetNeutrals.begin(), jetNeutrals.end(), pCur2 ) != jetNeutrals.end() ) continue;
245 
246  TVector3 vec2( pCur2->getMomentum() );
247 
248  double cosangle = vec2.Unit().Dot( jetMomentum.Unit() );
249  double invmass2 = pow( pCur2->getEnergy() + jetEnergy, 2 ) - ( jetMomentum + vec2 ).Mag2();
250  /*
251  cout << "Candidate particle found: energy = " << pCur2->getEnergy() << ", " ;
252  cout << "Direction: ( " << pCur2->getMomentum()[0] << ", " << pCur2->getMomentum()[1] << ", "
253  << pCur2->getMomentum()[2] << " ), charge = " << pCur2->getCharge()
254  << ", cosangle = " << cosangle << ", invmass = " << sqrt(invmass2) << endl;
255  */
256  if( cosangle < _tauCosAngle ) continue; // acceptance angle cut; skipped.
257  if( invmass2 > _tauMass*_tauMass ) continue; // invmass cut; skipped.
258 
259  //cout << "Candidate particle associated" << endl;
260 
261  jetEnergy += pCur2->getEnergy();
262  jetMomentum += vec2;
263  //pJet->addParticle(pCur2);
264  if( pCur2->getCharge() != 0. ){
265  // charge of lower track energy is ignored
266  if( pCur2->getEnergy() > _minimumTrackEnergyAssoc || _acceptFlexibleLowEnergyTrack ){
267  ntracks ++;
268  jetCharge += pCur2->getCharge();
269  jetTracks.push_back( pCur2 );
270  }
271  else{
272  // have to think about addition to eneutral
273  jetNeutrals.push_back( pCur2 );
274  }
275  }
276  else{
277  eneutral += pCur2->getEnergy();
278  jetNeutrals.push_back( pCur2 );
279  }
280  }
281  nPartAssocPriv = nPartAssoc;
282  nPartAssoc = jetTracks.size() + jetNeutrals.size();
283  }
284 
285  if(!_noSelection){
286  //cout << "primary selection" << endl;
287  // primary selection
288  if( jetEnergy < _minimumJetEnergy ){ continue; }
289 
290  // # tracks, charge selection
292  while( ( ntracks != 1 && ntracks != 3 ) || abs( int( jetCharge ) ) != 1 ){
293  ReconstructedParticle *p = jetTracks[ jetTracks.size()-1 ];
294  if( p->getEnergy() > _minimumTrackEnergyAssoc ) break;
295 
296  // removal of the track
297  jetCharge -= p->getCharge();
298  ntracks --;
299 
300  jetTracks.pop_back();
301 
302  // add to neutral instead
303  jetNeutrals.push_back(p);
304 
305  // cout << "Flexible low energy tracks: track treated as neutral: e = " << p->getEnergy() << ", c = " << p->getCharge();
306  //cout << ", ntracks now " << ntracks << ", jc = " << jetCharge << endl;
307 
308  }
309  }
310  if( ( ntracks != 1 && ntracks != 3 ) || abs( int( jetCharge ) ) != 1 ){ continue; }
311  }
312  // set RP
313  ReconstructedParticleImpl *pJet = new ReconstructedParticleImpl;
314 
315  pJet->setEnergy( jetEnergy );
316  double mom[3];
317  mom[0] = jetMomentum.x();
318  mom[1] = jetMomentum.y();
319  mom[2] = jetMomentum.z();
320  pJet->setMomentum( mom );
321  pJet->setCharge( jetCharge );
322 
323  // put into reconstructed jet: awkward method...
324  for( unsigned int n = 0; n < jetTracks.size(); n++ )
325  pJet->addParticle( jetTracks[n] );
326  for( unsigned int n = 0; n < jetNeutrals.size(); n++ )
327  pJet->addParticle( jetNeutrals[n] );
328 
329  if(!_noSelection){
330 
331  // 3prong + neutral rejection
332  if( ntracks == 3 && eneutral > _maximumNeutralEnergyInThreeProng ){ delete pJet; continue; }
333 
334  //cout << "cone selection" << endl;
335  // calculate cone energy
336  double econe = 0.;
337  for( int j = 0; j < nPart; j++ ) {
338  ReconstructedParticle *p = dynamic_cast< ReconstructedParticle* >( col->getElementAt(j) );
339 
340  // remove self
341  if( find( pJet->getParticles().begin(), pJet->getParticles().end(), p ) != pJet->getParticles().end() ) continue;
342 
343  TVector3 v( p->getMomentum() );
344  double cosangle = cos( v.Angle( jetMomentum ) );
345 
346  if( cosangle > _coneMinCosAngle && cosangle < _coneMaxCosAngle ){
347  econe += p->getEnergy();
348  //cout << "particle added to cone; costheta = " << cosangle << ", e = " << p->getEnergy() << ", charge = " << p->getCharge() << endl;
349  }
350  }
351  //cout << "econe = " << econe << ", jet energy = " << jetEnergy << endl;
352 
353  if( econe > _coneMaxEnergyFrac * jetEnergy ){ delete pJet; continue; }
354  }
355 
356  /*
357  if( ntracks == 3 && eneutral > 1. && econe > _coneMaxEnergyFrac * jetEnergy ){ delete pJet; continue; }
358 
359  if( (ntracks == 3 && eneutral > 1. ) || ( econe > _coneMaxEnergyFrac * jetEnergy ) ){
360  //if( ntracks == 3 && eneutral > 1. ) cout << "cone cut passed: move to IP cut." << endl;
361  //else cout << "cone cut rejected: move to IP cut." << endl;
362 
363  // IP cut
364  bool ipcutaccepted = false;
365  for( unsigned int j = 0; j < pJet->getParticles().size(); j++){
366  ReconstructedParticle *p = pJet->getParticles()[j];
367 
368  if( p->getCharge() == 0 ) continue; // track only
369  if( p->getTracks().size() == 0 ) continue; // skip with no tracks
370  if( p->getEnergy() < _ipCutsMinimumTrackEnergy ) continue; // too small energy track
371 
372  double d0 = p->getTracks()[0]->getD0();
373  double z0 = p->getTracks()[0]->getZ0();
374 
375  double d0err = sqrt(p->getTracks()[0]->getCovMatrix()[0]);
376  double z0err = sqrt(p->getTracks()[0]->getCovMatrix()[9]);
377 
378  //cout << "Track: d0 " << d0 << " d0err " << d0err << " z0 " << z0 << " z0err " << z0err << endl;
379 
380  // 3-prong, neutral
381  if( ntracks == 3 && eneutral > 1. &&
382  ( ( fabs( d0/d0err ) > _ipCutsSigmaThreeProngWithNeutrals || fabs( z0/z0err ) > _ipCutsSigmaThreeProngWithNeutrals ) &&
383  ( d0 < _ipMaxAbsolute && z0 < _ipMaxAbsolute ) ) ) ipcutaccepted = true;
384 
385  // 3-prong, no neutral
386  if( ntracks == 3 && eneutral < 1. &&
387  ( ( fabs( d0/d0err ) > _ipCutsSigmaThreeProngNoNeutrals || fabs( z0/z0err ) > _ipCutsSigmaThreeProngNoNeutrals ) &&
388  ( d0 < _ipMaxAbsolute && z0 < _ipMaxAbsolute ) ) ) ipcutaccepted = true;
389 
390  // 1-prong
391  if( ntracks == 1 &&
392  ( ( fabs( d0/d0err ) > _ipCutsSigmaOneProng || fabs( z0/z0err ) > _ipCutsSigmaOneProng ) &&
393  ( d0 < _ipMaxAbsolute && z0 < _ipMaxAbsolute ) ) ) ipcutaccepted = true;
394  }
395 
396  if( ntracks == 1 && eneutral < 1. && ipcutaccepted == false ){
397  //cout << "IP cut rejected: move to lepton ID cut." << endl;
398 
399  bool leptoncutaccepted = false;
400  for( unsigned int j = 0; j < pJet->getParticles().size(); j++ ){
401  ReconstructedParticle *p = pJet->getParticles()[j];
402 
403  if( p->getCharge() == 0 ) continue; // track only
404  if( p->getTracks().size() == 0 ) continue; // skip with no tracks
405  if( p->getClusters().size() == 0 ) continue; // skip with no neutrals
406  if( p->getEnergy() < _leptonCutsMinimumTrackEnergy ) continue; // too small energy track
407 
408  double ecal = p->getClusters()[0]->getSubdetectorEnergies()[0];
409  double hcal = p->getClusters()[0]->getSubdetectorEnergies()[1];
410  double tre = p->getEnergy();
411 
412  double fracecal = ecal / ( ecal + hcal );
413  double calbytrack = ( ecal + hcal ) / tre;
414 
415  //cout << "track for lepton ID: e = " << p->getEnergy() << " fracecal = " << fracecal << " calbytrack = " << calbytrack << endl;
416 
417  // muon ID
418  if( fracecal < _muMaxFracEcal && calbytrack < _muMaxCalByTrack ) leptoncutaccepted = true;
419  // electron ID
420  if( fracecal > _eMinFracEcal && calbytrack > _eMinCalByTrack && calbytrack < _eMaxCalByTrack ) leptoncutaccepted = true;
421  }
422  if( leptoncutaccepted == false ){
423  //cout << "lepton cut rejected: the jet is finally rejected." << endl;
424  delete pJet; continue;
425  }
426  }
427  else if( ipcutaccepted == false ){
428  //cout << "IP cut rejected: the jet is rejected." << endl;
429  delete pJet; continue;
430  }
431  }
432  */
433 
434  //cout << "The jet is accepted for tau!";
435  //cout << " e = " << jetEnergy << " : pz = " << jetMomentum.z() << " npart = " << pJet->getParticles().size() << endl;
436 
437  pTaJetsCol->addElement( pJet );
438  // remove from parts[]
439  for( int j = 0; j < nPart; j++ ) {
440  ReconstructedParticle *p = parts[j];
441  if(p == 0) continue;
442 
443  // remove self
444  if( find( pJet->getParticles().begin(), pJet->getParticles().end(), p ) != pJet->getParticles().end() ) parts[j] = 0;
445  }
446 
447  }
448  //cout << "Tau reconstruction result: " << pTaJetsCol->getNumberOfElements() << " jets found." << endl;
449  evt->addCollection( pTaJetsCol,_tauCollectionName );
450 
451  // make remaining collection
452  for( int j = 0; j < nPart; j++ ) {
453  ReconstructedParticle *p = parts[j];
454  if(p == 0) continue;
455 
456  pRemainCol->addElement(p);
457  }
458  evt->addCollection( pRemainCol, _remainCollectionName );
459 
460  //-- note: this will not be printed if compiled w/o MARLINDEBUG=1 !
461  streamlog_out(DEBUG) << " processing event: " << evt->getEventNumber()
462  << " in run: " << evt->getRunNumber()
463  << std::endl ;
464 
465  _nEvt ++ ;
466 }
467 
468 
469 
470 void TaJetClustering::check( LCEvent * /*evt*/ ) {
471  // nothing to check here - could be used to fill checkplots in reconstruction processor
472 }
473 
474 
476 
477 // std::cout << "TaJetClustering::end() " << name()
478 // << " processed " << _nEvt << " events in " << _nRun << " runs "
479 // << std::endl ;
480 
481 }
482 
virtual void processRunHeader(LCRunHeader *run)
Called for every run.
std::string _remainCollectionName
virtual void check(LCEvent *evt)
std::string _pfoCollectionName
Input collection name.
int _acceptFlexibleLowEnergyTrack
double _coneMaxEnergyFrac
virtual void processEvent(LCEvent *evt)
Called for every event - the working horse.
double _maximumNeutralEnergyInThreeProng
double _minimumTrackEnergyAssoc
double _minimumJetEnergy
TaJetClustering aTaJetClustering
virtual void init()
Called at the begin of the job before anything is read.
std::string _tauCollectionName
double _minimumTrackEnergy
std::vector< LCCollection * > LCCollectionVec
Definition: SiStripClus.h:55
virtual void end()
Called after data processing for clean up.
bool compareEnergy(ReconstructedParticle *const &p1, ReconstructedParticle *const &p2)