All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
GammaGammaCandidateFinder.cc
Go to the documentation of this file.
1 #include "EVENT/LCIO.h"
2 #include "EVENT/LCRunHeader.h"
3 #include "EVENT/LCCollection.h"
4 #include "EVENT/LCParameters.h"
5 #include "EVENT/ReconstructedParticle.h"
6 #include "IMPL/ReconstructedParticleImpl.h"
8 #include "CLHEP/Vector/LorentzVector.h"
9 #include "CLHEP/Vector/ThreeVector.h"
10 typedef CLHEP::HepLorentzVector LorentzVector ;
11 typedef CLHEP::Hep3Vector Vector3D ;
12 
13 // MarlinKinfit stuff
14 #include "JetFitObject.h"
15 #include "OPALFitterGSL.h"
16 #include "NewFitterGSL.h"
17 #include "NewtonFitterGSL.h"
18 #include "MassConstraint.h"
19 
20 // Marlin stuff
21 #include <marlin/Global.h>
22 // the event display
23 
24 // ROOT stuff
25 #include "TMath.h"
26 #include "TMatrixD.h"
27 
28 #include <cstdlib>
29 
30 using namespace lcio;
31 
33 
34 GammaGammaCandidateFinder::GammaGammaCandidateFinder() : marlin::Processor("GammaGammaCandidateFinder") {
35 
36  registerProcessorParameter( "Printing" ,
37  "Print certain messages" ,
38  _printing,
39  (int)1 ) ;
40 
41  std::string ggResonanceName = "Pi0";
42  registerProcessorParameter( "GammaGammaResonanceName" ,
43  "Particle decaying to Gamma Gamma" ,
45  ggResonanceName) ;
46 
47  std::string inputParticleCollectionName = "PandoraPFOs";
48  registerInputCollection( LCIO::RECONSTRUCTEDPARTICLE,
49  "InputParticleCollectionName" ,
50  "Input Particle Collection Name " ,
52  inputParticleCollectionName);
53 
54  std::string outputParticleCollectionName = "GammaGammaCandidates";
55  registerOutputCollection( LCIO::RECONSTRUCTEDPARTICLE,
56  "OutputParticleCollectionName" ,
57  "Output Particle Collection Name " ,
59  outputParticleCollectionName);
60 
61  registerProcessorParameter( "GammaMomentumCut" ,
62  "Minimum Momentum Cut for Photon (GeV)" ,
64  (float)0.5) ;
65 
66  registerProcessorParameter( "GammaGammaResonanceMass" ,
67  "Nominal Mass of Particle Decaying to Gamma Gamma (GeV)" ,
69  (float)0.135) ;
70 
71  registerProcessorParameter( "MaxDeltaMgg" ,
72  "Maximum difference between candidate mass and GammaGama Resonance mass (GeV)" ,
73  _dmggcut,
74  (float)0.040);
75 
76  registerProcessorParameter( "FitProbabilityCut" ,
77  "Minimum fit probability" ,
79  (double)0.001);
80 
81  registerProcessorParameter( "fitter" ,
82  "0 = OPALFitter, 1 = NewFitter, 2 = NewtonFitter",
83  _ifitter,
84  (int)0);
85 
86 
87  return;
88 
89 }
90 
91 //===================================================================================
92 
94  if(_printing>1)printParameters();
95  return;
96 }
97 
98 //===================================================================================
99 
100 void GammaGammaCandidateFinder::processRunHeader( LCRunHeader* /*run*/) {
101  return;
102 }
103 
104 //===================================================================================
105 
107 
108  // Make a new vector of particles
109  LCCollectionVec * recparcol = new LCCollectionVec(LCIO::RECONSTRUCTEDPARTICLE);
110 
111  // Access PFO collection
112  bool found = this->FindPFOs(evt);
113  if(found){
114  if(_printing>1)std::cout << "Analysis : " << _ggResonanceName << std::endl;
115  this->FindGammaGammaCandidates(recparcol);
116  }
117 
118  // Add new collection to event
119  evt->addCollection( recparcol , _outputParticleCollectionName.c_str() );
120 
121  return;
122 
123 }
124 
125 //===================================================================================
126 
128  return;
129 }
130 
131 //===================================================================================
132 
134 
135  bool tf = false;
136 
137  // clear old vector
138  _pfovec.clear();
139  typedef const std::vector<std::string> StringVec ;
140  StringVec* strVec = evt->getCollectionNames() ;
141  for(StringVec::const_iterator name=strVec->begin(); name!=strVec->end(); name++){
142  if(*name==_inputParticleCollectionName){
143  LCCollection* col = evt->getCollection(*name);
144  unsigned int nelem = col->getNumberOfElements();
145  tf = true;
146  for(unsigned int i=0;i<nelem;i++){
147  ReconstructedParticle* recoPart = dynamic_cast<ReconstructedParticle*>(col->getElementAt(i));
148  _pfovec.push_back(recoPart);
149  }
150  }
151  }
152 
153  if(_printing>1)std::cout << "Find PFOs : " << tf << std::endl;
154 
155  return tf;
156 
157 }
158 
159 //===================================================================================
160 
162 
163 // Take initial BestPi0 implementation and extend to all combinations consistent with pi0 mass
164 
165 // TODO : Check whether these things should be floats or doubles.
166 
167  if(_printing>1)std::cout << "FindGammaGammaCandidates : (nPFOs = " << _pfovec.size() << " )" << std::endl;
168 
169  // Look for photon candidates
170  std::vector<LorentzVector>pgamma;
171  std::vector<ReconstructedParticle*>pGammaPfoVec;
172 
173  for(unsigned int i=0;i<_pfovec.size();i++){
174 // Photon-ID
175 // Require charge = 0
176  if( fabs( _pfovec[i]->getCharge() - 0.0) < 0.5 ){
177  bool photon = true;
178 // Many neutral PFOs are not photons - so also explicitly reject if this is not identified as a photon
179  if(_pfovec[i]->getType()!=22)photon=false;
180 // Kinematic reduction of combinatorics with energy cut on accepted photons - but will also lose efficiency ...
181  if(_pfovec[i]->getEnergy()<_gammaMomentumCut)photon=false;
182  if(photon){
183  if(_printing>1)std::cout << "FindGammaGammaCandidates : Photon " << _pfovec[i]->getType() << std::endl;
184  LorentzVector pgam(_pfovec[i]->getMomentum()[0] ,_pfovec[i]->getMomentum()[1] ,_pfovec[i]->getMomentum()[2], _pfovec[i]->getEnergy() );
185  pgamma.push_back(pgam);
186  pGammaPfoVec.push_back(_pfovec[i]);
187  }
188  }
189  }
190 
191  if(_printing>1)std::cout << "FindGammaGammaCandidates : (nphotons = " << pGammaPfoVec.size() << " " << pgamma.size() << " )" << std::endl;
192 
193  // loop over pairs of candidate photons and keep all combinations consistent with the given parent mass assumption
194 
195  ReconstructedParticle* pGammai = NULL;
196  ReconstructedParticle* pGammaj = NULL;
197 
198  if(pgamma.size() >=2 ){
199  for(unsigned int i=0;i<pgamma.size()-1;i++){
200  for(unsigned int j=i+1;j<pgamma.size();j++){
201  LorentzVector pgg = pgamma[i]+pgamma[j];
202  float mgg = pgg.m();
203  if(_printing>2)std::cout << "Testing for " << _ggResonanceName << " " << i << " " << j << " M = " << mgg << std::endl;
204 // Select pairs consistent with resonance mass for further processing (storage and/or fitting)
205  if( fabs(mgg - _ggResonanceMass) < _dmggcut){
206 
207  pGammai = pGammaPfoVec[i];
208  pGammaj = pGammaPfoVec[j];
209 
210 // Set up mass constrained fit using code similar to WW5CFIT in MarlinKinfit
211 
212  double mass_constraint = double(_ggResonanceMass);
213  MassConstraint mc(mass_constraint);
214 
215  LorentzVector pgi = pgamma[i];
216  LorentzVector pgj = pgamma[j];
217 
218 // Note - we currently use hard-wired approximate error estimates partly because the covariance matrix of the
219 // photon 4-vectors is not yet properly filled on input
220 // TODO: Also need to account for the different/better errors implicit in photon conversions ..
221 
222  JetFitObject j1(pgi.e(), pgi.theta(), pgi.phi(),
223  0.16*std::sqrt(pgi.e()), 0.001/std::sqrt(pgi.e()), 0.001/std::sqrt(pgi.e()), 0.0);
224 // j1->setName("Photon1");
225  JetFitObject j2(pgj.e(), pgj.theta(), pgj.phi(),
226  0.16*std::sqrt(pgj.e()), 0.001/std::sqrt(pgj.e()), 0.001/std::sqrt(pgj.e()), 0.0);
227 // j2->setName("Photon2");
228 
229  mc.addToFOList(j1);
230  mc.addToFOList(j2);
231 
232 // Choose fit engine method according to the steering file option
233 
234  BaseFitter *pfitter;
235  if (_ifitter == 1) {
236  pfitter = new NewFitterGSL();
237  }
238  else if (_ifitter == 2) {
239  pfitter = new NewtonFitterGSL();
240  }
241  else {
242  pfitter = new OPALFitterGSL();
243  }
244  BaseFitter &fitter = *pfitter;
245 
246  fitter.addFitObject(j1);
247  fitter.addFitObject(j2);
248  fitter.addConstraint(mc);
249 
250  double fit_probability = 0.0;
251  fit_probability = fitter.fit();
252 
253  int nIterations = fitter.getIterations();
254 
255  int errorCode = fitter.getError();
256 
257  int cov_dim;
258  double * cov = fitter.getGlobalCovarianceMatrix(cov_dim); // 6x6
259 
260  if(_printing>3){
261  std::cout << "Constrained fit results RC: " << errorCode << std::endl;
262  std::cout << "Measured mass = " << mgg << std::endl;
263  std::cout << "No. of iterations " << nIterations << std::endl;
264  std::cout << "Fit probability = " << fit_probability << std::endl;
265  std::cout << "Covariance matrix dimension " << cov_dim << std::endl;
266  if(cov_dim==6){
267  for (unsigned int i=0; i<6*6; i++){
268  std::cout << "Covariance matrix element " << i << " " << cov[i] << std::endl;
269  }
270  }
271  }
272 
273  // Make the reconstructed particle using the result of the constrained fit
274  // likely need some minimal fit probability cut - configurable for each gamma-gamma hypothesis
275  ReconstructedParticleImpl * recoPart = new ReconstructedParticleImpl();
276  recoPart->addParticle(pGammai);
277  recoPart->addParticle(pGammaj);
278  double Energy;
279  double Mom[3];
280  // The 4-vector of the fitted gamma-gamma is the sum of the two fitted 4-vectors.
281 
282  // Get the individual fitted photon 4-vectors - needed to calculate the four-momentum covariance matrix of the gamma-gamma system
283  double Mom1[3],Mom2[3];
284  double E1,E2;
285  double pT1,pT2;
286 
287  E1 = j1.getE();
288  Mom1[0] = j1.getPx();
289  Mom1[1] = j1.getPy();
290  Mom1[2] = j1.getPz();
291  pT1 = sqrt(Mom1[0]*Mom1[0] + Mom1[1]*Mom1[1]);
292 
293  E2 = j2.getE();
294  Mom2[0] = j2.getPx();
295  Mom2[1] = j2.getPy();
296  Mom2[2] = j2.getPz();
297  pT2 = sqrt(Mom2[0]*Mom2[0] + Mom2[1]*Mom2[1]);
298 
299  Energy = E1 + E2;
300  Mom[0] = Mom1[0] + Mom2[0];
301  Mom[1] = Mom1[1] + Mom2[1];
302  Mom[2] = Mom1[2] + Mom2[2];
303 
304  FloatVec covP(10, 0.0);
305  // (px,py,pz,E)
306 
307  // Follow for now implementation in FourMomentumCovMat based on TMatrixD
308 
309  if(cov_dim == 6 ){
310  // Note some cases of cov_dim != 6 have been seen ...
311  const int nrows = 6; // n rows jacobian
312  const int ncolumns = 4; // n columns jacobian
313 
314  // Transformation matrix D (6*4) between (E1, theta1, phi1, E2, theta2, phi2) and (px, py, pz, E)
315  double jacobian_by_columns[nrows*ncolumns] = {
316  Mom1[0]/E1, Mom1[0]*Mom1[2]/pT1, -Mom1[1], Mom2[0]/E2, Mom2[0]*Mom2[2]/pT2, -Mom2[1],
317  Mom1[1]/E1, Mom1[1]*Mom1[2]/pT1, Mom1[0], Mom2[1]/E2, Mom2[1]*Mom2[2]/pT2, Mom2[0],
318  Mom1[2]/E1, -pT1 , 0.0 , Mom2[2]/E2, -pT2 , 0.0 ,
319  1.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 };
320 
321  // Now set up to calculate the new covariance matrix, namely V' = D^T V D
322  TMatrixD Dmatrix(nrows,ncolumns, jacobian_by_columns, "F");
323  TMatrixD Vmatrix(nrows,nrows, cov, "F"); // May need to have the filling array explicitly dimensioned ??
324  TMatrixD Covmatrix(ncolumns,ncolumns); // Hopefully this is good enough for initialization ?
325 
326  Covmatrix.Mult( TMatrixD( Dmatrix, TMatrixD::kTransposeMult, Vmatrix) ,Dmatrix); // Is this what we want ?
327 
328  for(int ii=0;ii<4;ii++){
329  for(int jj=0;jj<4;jj++){
330  if(_printing>3)std::cout << "4-vector cov. " << ii << " " << jj << " " << Covmatrix(ii,jj) << std::endl;
331  }
332  }
333 
334  covP[0] = Covmatrix(0,0); // px-px
335  covP[1] = Covmatrix(0,1); // px-py
336  covP[2] = Covmatrix(1,1); // py-py
337  covP[3] = Covmatrix(0,2); // px-pz
338  covP[4] = Covmatrix(1,2); // py-pz
339  covP[5] = Covmatrix(2,2); // pz-pz
340  covP[6] = Covmatrix(0,3); // px-E
341  covP[7] = Covmatrix(1,3); // py-E
342  covP[8] = Covmatrix(2,3); // pz-E
343  covP[9] = Covmatrix(3,3); // E-E
344  }
345  else{
346  if(_printing>1)std::cout << " Fit has no valid covariance information (cov_dim = " << cov_dim << " )" << std::endl;
347  }
348 
349  recoPart->setEnergy( Energy );
350  recoPart->setMomentum( Mom );
351  recoPart->setMass( mass_constraint );
352  recoPart->setCharge( 0.0 );
353  recoPart->setCovMatrix( covP );
354 
355  // For now - store the fit probability in the goodnessofPiD variable
356  float goodnessOfPID = float(fit_probability);
357 // if( mgg < _ggResonanceMass)goodnessOfPID = - goodnessOfPID;
358  recoPart->setGoodnessOfPID( goodnessOfPID );
359 
360  // Default choice is Pi0
361  recoPart->setType( 111 );
362  if(_ggResonanceName=="Eta")recoPart->setType( 221 );
363  if(_ggResonanceName=="EtaPrime")recoPart->setType( 331 );
364 
365  if(_printing>1)std::cout << "Fitting " << _ggResonanceName << " gg candidate M= "
366  << mgg << " " << i << " " << j << " " << pgi.e() << " " << pgj.e() <<
367  " Fitted energies: " << j1.getE() << " " << j2.getE()
368  << " Fit probability = " << fit_probability << std::endl;
369 
370  // Add it to the collection if it exceeds the required miminum fit probability
371  if(fit_probability > _fitProbabilityCut){
372  if(_printing>1)std::cout << "GG candidate passes fit probability cut - KEEP" << std::endl;
373  recparcol->addElement( recoPart );
374  }
375  }
376  }
377  }
378  }
379 
380  return;
381 }
virtual void end()
Called after data processing for clean up.
CLHEP::Hep3Vector Vector3D
GammaGammaCandidateFinder aGammaGammaCandidateFinder
void FindGammaGammaCandidates(LCCollectionVec *)
virtual void processRunHeader(LCRunHeader *run)
Called for every run.
GammaGammaCandidateFinder:
virtual void init()
Called at the beginning of the job before anything is read.
CLHEP::HepLorentzVector LorentzVector
std::vector< LCCollection * > LCCollectionVec
Definition: SiStripClus.h:55
virtual void processEvent(LCEvent *evt)
Called for every event - the working horse.
std::vector< ReconstructedParticle * > _pfovec
std::vector< std::string > StringVec
Definition: SiStripClus.h:56