All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
TPCDigiProcessor.cc
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 
3 #include "TPCDigiProcessor.h"
4 #include <iostream>
5 #include <iomanip>
6 #include <vector>
7 #include <map>
8 #include <cmath>
9 #include <algorithm>
10 
11 #include <gsl/gsl_randist.h>
12 #include "marlin/VerbosityLevels.h"
13 #include "marlin/ProcessorEventSeeder.h"
14 
15 #include "Circle.h"
16 #include "SimpleHelix.h"
17 #include"constants.h"
18 #include "LCCylinder.h"
19 #include <IMPL/LCFlagImpl.h>
20 #include <IMPL/LCRelationImpl.h>
21 
22 //stl exception handler
23 #include <stdexcept>
24 #include "constants.h"
25 #include "voxel.h"
26 
27 // STUFF needed for GEAR
28 #include <marlin/Global.h>
29 #include <gear/GEAR.h>
30 #include <gear/TPCParameters.h>
31 #include <gear/PadRowLayout2D.h>
32 #include <gear/BField.h>
33 //
34 #include "UTIL/LCTrackerConf.h"
35 #include <UTIL/ILDConf.h>
36 
37 using namespace lcio ;
38 using namespace marlin ;
39 using namespace constants ;
40 using namespace std ;
41 
42 #ifdef MARLIN_USE_AIDA
43 using namespace AIDA ;
44 #endif
45 
46 
48 
50  return ( a->getPhiIndex() < b->getPhiIndex() ) ;
51 }
52 
53 bool compare_z( Voxel_tpc* a, Voxel_tpc* b) {
54  return ( a->getZIndex() < b->getZIndex() ) ;
55 }
56 
57 
58 TPCDigiProcessor::TPCDigiProcessor() : Processor("TPCDigiProcessor")
59 {
60 
61  // modify processor description
62  _description = "Produces TPC TrackerHit collection from SimTrackerHit collection, smeared in RPhi and Z. A search is made for adjacent hits on a pad row, if they are closer in z and r-phi than the steering parameters _doubleHitResRPhi (default value 2.0 mm) and _doubleHitResZ (default value 5.0 mm) they are considered to overlap. Clusters of hits smaller than _maxMerge (default value 3) are merged into a single tracker hit, with the position given as the average poision of the hits in phi and in z. Clusters which have _maxMerge hits or more are determined to be identifiable as multiple hits, and are not added to the tracker hit collection. This of course means that good hits caught up in a cluster of background hits will be lossed." ;
63 
64  // register steering parameters: name, description, class-variable, default value
65 
66  registerInputCollection( LCIO::SIMTRACKERHIT,
67  "TPCPadRowHitCollectionName" ,
68  "Name of the default pad-row based SimTrackerHit collection" ,
70  std::string("TPCCollection") ) ;
71 
72  registerInputCollection( LCIO::SIMTRACKERHIT,
73  "TPCSpacePointCollectionName" ,
74  "Name of the additional space point collection which provides additional guide hits between pad row centers." ,
76  std::string("TPCSpacePointCollection") ) ;
77 
78  registerInputCollection( LCIO::SIMTRACKERHIT,
79  "TPCLowPtCollectionName" ,
80  "Name of the LowPt SimTrackerHit collection Produced by Mokka TPC Driver TPC0X" ,
82  std::string("TPCLowPtCollection") ) ;
83 
84  registerOutputCollection( LCIO::TRACKERHIT,
85  "TPCTrackerHitsCol" ,
86  "Name of the Output TrackerHit collection" ,
88  std::string("TPCTrackerHits") ) ;
89 
90  registerOutputCollection(LCIO::LCRELATION,
91  "SimTrkHitRelCollection",
92  "Name of TrackerHit SimTrackHit relation collection",
94  std::string("TPCTrackerHitRelations"));
95 
96  registerProcessorParameter("UseRawHitsToStoreSimhitPointer",
97  "Store the pointer to the SimTrackerHits in RawHits (deprecated) ",
99  bool(false));
100 
101  registerProcessorParameter( "PointResolutionPadPhi" ,
102  "Pad Phi Resolution constant in TPC" ,
104  (float)0.900) ;
105 
106  registerProcessorParameter( "RejectCellID0" ,
107  "whether or not to use hits without proper cell ID (pad row)" ,
109  (int)1) ;
110 
111  registerProcessorParameter( "PointResolutionRPhi" ,
112  "R-Phi Resolution constant in TPC" ,
114  (float)0.050) ;
115 
116  registerProcessorParameter( "DiffusionCoeffRPhi" ,
117  "R-Phi Diffusion Coefficent in TPC" ,
118  _diffRPhi ,
119  (float)0.025) ;
120 
121  registerProcessorParameter( "N_eff" ,
122  "Number of Effective electrons per pad in TPC" ,
123  _nEff ,
124  (int)22) ;
125 
126  registerProcessorParameter( "PointResolutionZ" ,
127  "TPC Z Resolution Coefficent independent of diffusion" ,
128  _pointResoZ0 ,
129  (float)0.4) ;
130 
131  registerProcessorParameter( "DiffusionCoeffZ" ,
132  "Z Diffusion Coefficent in TPC" ,
133  _diffZ ,
134  (float)0.08) ;
135 
136  registerProcessorParameter( "HitSortingBinningZ" ,
137  "Defines spatial slice in Z" ,
138  _binningZ ,
139  (float)5.0) ;
140 
141  registerProcessorParameter( "HitSortingBinningRPhi" ,
142  "Defines spatial slice in RP" ,
143  _binningRPhi ,
144  (float)2.0) ;
145 
146 
147  registerProcessorParameter( "DoubleHitResolutionZ" ,
148  "Defines the minimum distance for two seperable hits in Z" ,
150  (float)5.0) ;
151 
152  registerProcessorParameter( "DoubleHitResolutionRPhi" ,
153  "Defines the minimum distance for two seperable hits in RPhi" ,
155  (float)2.0) ;
156 
157  registerProcessorParameter( "MaxClusterSizeForMerge" ,
158  "Defines the maximum number of adjacent hits which can be merged" ,
159  _maxMerge ,
160  (int)3) ;
161 
162  registerProcessorParameter( "DontEncodeSide" ,
163  "Do not encode the side in the cellID of the TrackerHit",
165  (bool) true ) ;
166 }
167 
168 
170 {
171 
172 
173  // From GNU documentation:
174  // A replacement for the standard terminate_handler which prints
175  // more information about the terminating exception (if any) on stderr. Call ...
176  //std::set_terminate (__gnu_cxx::__verbose_terminate_handler);
177 
178 #ifdef DIGIPLOTS
179  /// Hook an AIDA implementation -----------------------------------------------
180 
181  // First create a pointer to the "IAnalysisFactory" of a specific AIDA
182  // implementation. This factory can then be used to produce all other
183  // factories.
184  _AF = AIDA_createAnalysisFactory();
185 
186  // Create a ITreeFactory. -----------------------------------------------------
187  // A ITree can be used to store AIDA objects in memory or on disk.
188 
189  _TRF = _AF->createTreeFactory();
190 
191  /// Create a ITree object which is bound to a file. ---------------------------
192  // You must always create a "ITree" object to create any other factory.
193  /*
194  * Creates a new tree and associates it with a store.
195  * The store is assumed to be read/write.
196  * The store will be created if it does not exist.
197  * @param storeName The name of the store, if empty (""), the tree is
198  * created in memory and therefore will not be associated
199  * with a file.
200  * @param storeType Implementation specific string, may control store type
201  * @param readOnly If true the store is opened readonly, an exception if it
202  * does not exist
203  * @param createNew If false the file must exist, if true the file will be
204  * created
205  * @param options Other options, currently are not specified
206  */
207  // ITree * ITreeFactory::create(const std::string & storeName,
208  // const std::string & storeType = "",
209  // bool readOnly = false,
210  // bool createNew = false,
211  // const std::string & options = "") ;
212 
213  _TREE = _TRF->create("TPCDigi.root",
214  "root",
215  false,
216  true);
217 
218  /// Create an IHistogramFactory which is bound to the tree "*_TREE". -----------
219 
220  /*
221  * Create an IHistogramFactory.
222  * @param tree The ITree which created histograms will be associated to.
223  * @return The IHistogramFactory.
224  */
225  // IHistogramFactory * IAnalysisFactory::createHistogramFactory(ITree & tree);
226 
227  _HF = _AF->createHistogramFactory(*_TREE);
228 
229  _TREE->mkdir("Histograms");
230 
231  /*
232  * Create a IHistogram1D.
233  * @param path The path of the created IHistogram. The path can either
234  * be a relative or full path.
235  * ("/folder1/folder2/dataName" and
236  * "../folder/dataName" are valid paths).
237  * All the directories in the path must exist. The
238  * characther `/` cannot be used in names; it is only
239  * used to delimit directories within paths.
240  * @param title The title of the IHistogram1D.
241  * @param nBins The number of bins of the x axis.
242  * @param lowerEdge The lower edge of the x axis.
243  * @param upperEdge The upper edge of the x axis.
244  * @param options The options for the IHistogram1D. The default is "".
245  * "type=efficiency" for an efficiency IHistogram1D.
246  * @return The newly created IHistogram1D.
247  */
248 
249 
250 
251  _phiDiffHisto = _HF->createHistogram1D("Histograms/phi_diff",
252  "Calculated Phi - Track Phi",
253  201, -0.05, 0.05);
254 
255  _thetaDiffHisto = _HF->createHistogram1D("Histograms/theta_diff",
256  "Calculated Theta - Track Theta",
257  201, -0.05, 0.05);
258 
259  _phiRelHisto = _HF->createHistogram1D("Histograms/padPhi",
260  "Phi Relative to the Pad",
261  201, 0.0, 6.3);
262 
263  _thetaRelHisto = _HF->createHistogram1D("Histograms/padtheta",
264  "Theta Relative to the pad",
265  201, 0.0, 6.3);
266 
267  _rPhiDiffHisto = _HF->createHistogram1D("Histograms/rPhiDiff",
268  "rPhi_rec - rPhi_sim",
269  201, -1.0, 1.0);
270 
271  _zDiffHisto = _HF->createHistogram1D("Histograms/zDiff",
272  "Z_rec - Z_sim",
273  201, -1.0, 1.0);
274 
275  _zPullHisto = _HF->createHistogram1D("Histograms/zPull",
276  "(z_rec - z_sim) / Sigma_z",
277  201, -10.0, 10.0);
278 
279  _phiDistHisto = _HF->createHistogram1D("Histograms/phiDist",
280  "phi_rec - Phi_sim",
281  201, -1.0, 1.0);
282 
283  _rPhiPullHisto = _HF->createHistogram1D("Histograms/rPhiPull",
284  "(rPhi_rec - rPhi_sim) / Sigma_rPhi",
285  201, -10.0, 10.0);
286 
287  _zSigmaVsZHisto = _HF->createHistogram2D("Histograms/zSigmaVsZ",
288  "z Sigma vs Z ",
289  3000, 0.0, 3000.0,
290  201, -0.20, 5.20);
291 
292  _zSigmaHisto = _HF->createHistogram1D("Histograms/zSigma",
293  "z Sigma ",
294  201, -0.20, 5.20);
295 
296  _rPhiSigmaHisto = _HF->createHistogram1D("Histograms/rPhiSigma",
297  "rPhi Sigma",
298  201, -0.20, 0.20);
299 
300  _radiusCheckHisto = _HF->createHistogram1D("Histograms/radiusCheck",
301  "R_hit - TPC Rmin - ((RowIndex + 0.5 )* padheight)",
302  201, -0.20, 0.20);
303 
304  _ResidualsRPhiHisto = _HF->createHistogram1D("Histograms/ResidualsRPhi",
305  "MC Track Phi - Hit Phi",
306  50, -0.001, 0.001);
307 
308  _NSimTPCHitsHisto = _HF->createHistogram1D("Histograms/SimTPCHits",
309  "Number of SimTPC Hits",
310  100, 0.0, 1000000.0);
311 
312  _NBackgroundSimTPCHitsHisto = _HF->createHistogram1D("Histograms/NBackgroundSimTPCHits",
313  "Number of Background SimTPC Hits",
314  100, 0.0, 1000000.0);
315 
316  _NPhysicsSimTPCHitsHisto = _HF->createHistogram1D("Histograms/NPhysicsSimTPCHits",
317  "Number of PhysicsSimTPC Hits",
318  100, 0.0, 100000.0);
319 
320  _NPhysicsAbove02GeVSimTPCHitsHisto = _HF->createHistogram1D("Histograms/NPhysicsAbove02GeVTPCHits",
321  "Number of PhysicsSimTPC Hits above 0.2GeV pt",
322  100, 0.0, 100000.0);
323 
324  _NPhysicsAbove1GeVSimTPCHitsHisto = _HF->createHistogram1D("Histograms/NPhysicsAbove1GeVPtTPCHits",
325  "Number of PhysicsSimTPC Hits above 1.0 GeV pt",
326  100, 0.0, 100000.0);
327 
328  _NRecTPCHitsHisto = _HF->createHistogram1D("Histograms/NRecTPCHits",
329  "Number of Rec TPC Hits",
330  50, 0.0, 100000.0);
331 
332  _NLostPhysicsTPCHitsHisto = _HF->createHistogram1D("Histograms/NLostPhysicsTPCHits",
333  "Number of PhysicsSimTPC Hits Lost",
334  100, 0.0, 5000.0);
335 
336  _NLostPhysicsAbove02GeVPtTPCHitsHisto = _HF->createHistogram1D("Histograms/NLostPhysicsAbove02GeVPtTPCHits",
337  "Number of PhysicsSimTPC Hits Lost above 0.2 GeV pt",
338  100, 0.0, 5000.0);
339 
340  _NLostPhysicsAbove1GeVPtTPCHitsHisto = _HF->createHistogram1D("Histograms/NLostPhysicsAbove1GeVPtTPCHits",
341  "Number of PhysicsSimTPC Hits Lost above 1.0 GeV pt",
342  100, 0.0, 1000.0);
343 
344  _NRevomedHitsHisto = _HF->createHistogram1D("Histograms/NRevomedHits",
345  "Number of Removed TPC hits",
346  100, 0.0, 1000000.0);
347 
348 
349  _NKeptPhysicsTPCHitsHistoPercent = _HF->createHistogram1D("Histograms/NKeptPhysicsTPCHitsPercent",
350  "Number of PhysicsSimTPC Hits Kept",
351  303, 0.0, 1.01);
352 
353  _NKeptPhysicsAbove02GeVPtTPCHitsHistoPercent = _HF->createHistogram1D("Histograms/NKeptPhysicsAbove02GeVPtTPCHitsPercent",
354  "Number of PhysicsSimTPC Hits Kept above 0.2 GeV pt",
355  303, 0.0, 1.01);
356 
357  _NKeptPhysicsAbove1GeVPtTPCHitsHistoPercent = _HF->createHistogram1D("Histograms/NKeptPhysicsAbove1GeVPtTPCHitsPercent",
358  "Number of PhysicsSimTPC Hits Kept above 1.0 GeV pt",
359  303, 0.0, 1.01);
360 
361 #endif
362 
363 
364  printParameters() ;
365 
366  //intialise random number generator
367  _random = gsl_rng_alloc(gsl_rng_ranlxs2);
368  Global::EVENTSEEDER->registerProcessor(this);
369 
370  _cellid_encoder = 0 ;
371  _nRun = 0 ;
372  _nEvt = 0 ;
373 
374 }
375 
376 void TPCDigiProcessor::processRunHeader( LCRunHeader* /*run*/)
377 {
378  _nRun++ ;
379 }
380 
381 void TPCDigiProcessor::processEvent( LCEvent * evt )
382 {
383 
384  gsl_rng_set( _random, Global::EVENTSEEDER->getSeed(this) ) ;
385  streamlog_out( DEBUG ) << "seed set to " << Global::EVENTSEEDER->getSeed(this) << " for event number "<< evt->getEventNumber() << std::endl;
386 
387  int numberOfVoxelsCreated(0);
388 
389  _NSimTPCHits = 0;
394  _NRecTPCHits = 0;
395 
399  _NRevomedHits = 0;
400 
401  static bool firstEvent = true;
402  _tpcHitMap.clear();
403  _tpcRowHits.clear();
404 
405  streamlog_out(DEBUG8) << " ========= processing event "
406  << std::setw(9) << evt->getEventNumber() << " run "
407  << std::setw(9) << evt->getRunNumber()
408  << " ========= " << endl;
409 
410 
411  if(firstEvent==true) {
413 
414  streamlog_out( DEBUG4 ) << "The relations to SimTrackerHits are now stored in relation collection " << _outRelColName << "\n SimTrackerHits are no longer stored in RawTrackerHits. Enable this deprecated feature by setting UseRawHitsToStoreSimhitPointer to true in steering file." << std::endl;
415 
416  }
417  else{
418 
419  streamlog_out( DEBUG4 ) << "SimTrackerHits will be stored in RawTrackerHits. This is a deprecated please use the relations stored in " << _outRelColName << std::endl;
420 
421  }
422 
423 
424  }
425 
426  firstEvent = false ;
427 
428  const gear::TPCParameters& gearTPC = Global::GEAR->getTPCParameters() ;
429  const gear::PadRowLayout2D& padLayout = gearTPC.getPadLayout() ;
430  // this gets the center of the first pad in the pad layout
431  const gear::Vector2D padCoord = padLayout.getPadCenter(1) ;
432 
433  // this assumes that the pad width in r*phi is the same for all pads
434  _padWidth = padLayout.getPadWidth(0)*padCoord[0];
435  // set size of row_hits to hold (n_rows) vectors
436  _tpcRowHits.resize(padLayout.getNRows());
437 
438  // created the collection which will be written out
439  _trkhitVec = new LCCollectionVec( LCIO::TRACKERHIT ) ;
440  _relCol = new LCCollectionVec(LCIO::LCRELATION);
441 
442  // to store the weights
443  LCFlagImpl lcFlag(0) ;
444  lcFlag.setBit( LCIO::LCREL_WEIGHTED ) ;
445  _relCol->setFlag( lcFlag.getFlag() ) ;
446 
447  _cellid_encoder = new CellIDEncoder<TrackerHitImpl>( lcio::LCTrackerCellID::encoding_string() , _trkhitVec ) ;
448 
449  // first deal with the pad-row based hits from Mokka
450  LCCollection* STHcol = 0 ;
451  try{
452  STHcol = evt->getCollection( _padRowHitColName ) ;
453  }
454  catch(DataNotAvailableException &e){
455  }
456 
457  float edep=0.0;
458  if( STHcol != 0 ){
459 
460  int n_sim_hits = STHcol->getNumberOfElements() ;
461 
462  LCFlagImpl colFlag( STHcol->getFlag() ) ;
463 
464  _NSimTPCHits = n_sim_hits;
465 
466  streamlog_out(DEBUG4) << "number of Pad-Row based SimHits = " << n_sim_hits << std::endl;
467 
468 
469  // make sure that all the pointers are initialise to NULL
470  _mcp=NULL;
471  _previousMCP=NULL;
472  _nextMCP=NULL;
473  _nMinus2MCP=NULL;
474  _nPlus2MCP=NULL;
475 
476  _SimTHit=NULL;
477  _previousSimTHit=NULL;
478  _nextSimTHit=NULL;
479  _nMinus2SimHit=NULL;
480  _nPlus2SimHit=NULL;
481 
482  // loop over all the pad row based sim hits
483  for(int i=0; i< n_sim_hits; i++){
484 
485  // this will used for nominaml smearing for very low pt rubish, so set it to zero initially
486  double ptSqrdMC = 0;
487 
488  _SimTHit = dynamic_cast<SimTrackerHit*>( STHcol->getElementAt( i ) ) ;
489 
490  float edep;
491  double padPhi(0.0);
492  double padTheta (0.0);
493 
494 
495  streamlog_out(DEBUG3) << "processing hit " << i << std::endl;
496  streamlog_out(DEBUG3) << " address = " << _SimTHit
497  << " x = " << _SimTHit->getPosition()[0]
498  << " y = " << _SimTHit->getPosition()[1]
499  << " z = " << _SimTHit->getPosition()[2]
500  << std::endl ;
501 
502 
503 
504  CLHEP::Hep3Vector thisPoint(_SimTHit->getPosition()[0],_SimTHit->getPosition()[1],_SimTHit->getPosition()[2]);
505  double padheight = padLayout.getPadHeight(padLayout.getNearestPad(thisPoint.perp(),thisPoint.phi()));
506 
507  const double bField = Global::GEAR->getBField().at( gear::Vector3D( 0., 0., 0.) ).z() ;
508  // conversion constant. r = pt / (FCT*bField)
509  const double FCT = 2.99792458E-4;
510 
511  _mcp = _SimTHit->getMCParticle() ;
512 
513  // increase the counters for the different classification of simhits
514  if(_mcp){
515 
516  // get the pt of the MCParticle, this will used later to uses nominal smearing for low momentum rubish
517  const double *momentumMC = _mcp->getMomentum();
518  ptSqrdMC = momentumMC[0]*momentumMC[0]+momentumMC[1]*momentumMC[1] ;
519 
520  streamlog_out(DEBUG3) << " mcp address = " << _mcp
521  << " px = " << momentumMC[0]
522  << " py = " << momentumMC[1]
523  << " pz = " << momentumMC[2]
524  << std::endl ;
525 
526  // SJA:FIXME: the fact that it is a physics hit relies on the fact that for overlay
527  // the pointer to the mcp is set to NULL. This distinction may not always be true ...
529  if( ptSqrdMC > (0.2*0.2) ) ++_NPhysicsAbove02GeVSimTPCHits ;
530  if( ptSqrdMC > 1.0 ) ++_NPhysicsAbove1GeVSimTPCHits ;
531 
532 #ifdef DIGIPLOTS
533  if(_mcp) plotHelixHitResidual(_mcp, &thisPoint);
534 #endif
535  } else {
537  }
538 
539  // if the hits contain the momentum of the particle use this to calculate the angles relative to the pad
540  if(colFlag.bitSet(LCIO::THBIT_MOMENTUM)) {
541 
542  const float * mcpMomentum = _SimTHit->getMomentum() ;
543 
544  CLHEP::Hep3Vector mom(mcpMomentum[0],mcpMomentum[1],mcpMomentum[2]);
545 
546  // const double pt = mom.perp();
547  // const double radius = pt / (FCT*bField);
548 
549  // const double tanLambda = mom.z()/pt;
550 
551  padPhi = fabs(thisPoint.deltaPhi(mom));
552  padTheta = mom.theta();
553 
554  }
555 
556  else { // LCIO::THBIT_MOMENTUM not set
557 
558  // as the momentum vector is not available from the hits use triplets of
559  // hits to fit a circle and calculate theta and phi relative to the pad
560 
561  if (!_mcp || (sqrt(ptSqrdMC) / (FCT*bField)) < ( padheight / (0.1 * twopi))) {
562  // if the hit has no record of it MCParticle then there is no way to know if this hit has consecutive hits from the same MCParticle
563  // so just set nominal values theta=phi=90
564  // here make a cut for particles which will suffer more than a 10 percent change in phi over the distance of the pad
565  // R > padheight/(0.1*2PI)
566  // in both cases set the angles to 90 degrees
567  padTheta = twopi/4.0 ;
568  padPhi = twopi/4.0 ;
569  }
570  else{
571 
572  // if there is at least one more hit after this one, set the pointer to the MCParticle for the next hit
573  if (i < (n_sim_hits-1) ) {
574  _nextSimTHit = dynamic_cast<SimTrackerHit*>( STHcol->getElementAt( i+1 ) ) ;
575  _nextMCP = _nextSimTHit->getMCParticle() ;
576  }
577  else{ // set make sure that the pointers are set back to NULL so that the comparisons later hold
578  _nextSimTHit = NULL;
579  _nextMCP = NULL;
580  }
581  // if there is at least two more hits after this one, set the pointer to the MCParticle for the next but one hit
582  if (i < (n_sim_hits-2) ) {
583  _nPlus2SimHit = dynamic_cast<SimTrackerHit*>( STHcol->getElementAt( i+2 ));
584  _nPlus2MCP = _nPlus2SimHit->getMCParticle() ;
585  }
586  else{ // set make sure that the pointers are set back to NULL so that the comparisons later hold
587  _nPlus2SimHit = NULL;
588  _nPlus2MCP = NULL;
589  }
590 
591  if ( _mcp==_previousMCP && _mcp==_nextMCP ) { // middle hit of 3 from the same MCParticle
592 
593  CLHEP::Hep3Vector precedingPoint(_previousSimTHit->getPosition()[0],_previousSimTHit->getPosition()[1],_previousSimTHit->getPosition()[2]) ;
594  CLHEP::Hep3Vector followingPoint(_nextSimTHit->getPosition()[0],_nextSimTHit->getPosition()[1],_nextSimTHit->getPosition()[2]) ;
595 
596  streamlog_out(DEBUG3) << "address of _previousSimTHit = " << _previousSimTHit
597  << " x = " << _previousSimTHit->getPosition()[0]
598  << " y = " << _previousSimTHit->getPosition()[1]
599  << " z = " << _previousSimTHit->getPosition()[2]
600  << std::endl ;
601 
602  streamlog_out(DEBUG4) << "address of _nextSimTHit = " << _nextSimTHit
603  << " x = " << _nextSimTHit->getPosition()[0]
604  << " y = " << _nextSimTHit->getPosition()[1]
605  << " z = " << _nextSimTHit->getPosition()[2]
606  << std::endl ;
607 
608  // get phi and theta using functions defined below
609  padPhi = getPadPhi( &thisPoint, &precedingPoint, &thisPoint, &followingPoint);
610  padTheta = getPadTheta(&precedingPoint, &thisPoint, &followingPoint);
611 
612  }
613  else if ( _mcp==_nextMCP && _mcp==_nPlus2MCP ) { // first hit of 3 from the same MCParticle
614 
615  CLHEP::Hep3Vector followingPoint(_nextSimTHit->getPosition()[0],_nextSimTHit->getPosition()[1],_nextSimTHit->getPosition()[2]) ;
616  CLHEP::Hep3Vector nPlus2Point(_nPlus2SimHit->getPosition()[0],_nPlus2SimHit->getPosition()[1],_nPlus2SimHit->getPosition()[2]) ;
617 
618  // get phi and theta using functions defined below
619  padPhi = getPadPhi( &thisPoint, &thisPoint, &followingPoint, &nPlus2Point);
620  padTheta = getPadTheta(&thisPoint, &followingPoint, &nPlus2Point);
621 
622  }
623  else if ( _mcp==_previousMCP && _mcp==_nMinus2MCP ) { // last hit of 3 from the same MCParticle
624 
625  CLHEP::Hep3Vector nMinus2Point(_nMinus2SimHit->getPosition()[0],_nMinus2SimHit->getPosition()[1],_nMinus2SimHit->getPosition()[2]);
626  CLHEP::Hep3Vector precedingPoint(_previousSimTHit->getPosition()[0],_previousSimTHit->getPosition()[1],_previousSimTHit->getPosition()[2]);
627 
628  // get phi and theta using functions defined below
629  padPhi = getPadPhi( &thisPoint, &nMinus2Point, &precedingPoint, &thisPoint);
630  padTheta = getPadTheta(&nMinus2Point, &precedingPoint, &thisPoint);
631 
632  }
633  else{ // the hit is isolated as either a single hit, or a pair of hits, from a single MCParticle
634  padTheta = twopi/4.0 ;
635  padPhi = twopi/4.0 ;
636  }
637  }
638 
639 #ifdef DIGIPLOTS
640  if(colFlag.bitSet(LCIO::THBIT_MOMENTUM)) {
641 
642  const float * mcpMomentum = _SimTHit->getMomentum() ;
643 
644  CLHEP::Hep3Vector mom(mcpMomentum[0],mcpMomentum[1],mcpMomentum[2]);
645 
646  double trackPhi = mom.phi();
647 
648  if(trackPhi<0.0) trackPhi=trackPhi+twopi;
649  if(trackPhi>twopi) trackPhi=trackPhi-twopi;
650  if(trackPhi>twopi/2.0) trackPhi = trackPhi - twopi/2.0 ;
651 
652  double localPhi = thisPoint.phi() - padPhi;
653 
654  _phiRelHisto->fill(padPhi);
655  _phiDiffHisto->fill((fabs(localPhi - trackPhi))/trackPhi);
656  _thetaRelHisto->fill(padTheta);
657  _thetaDiffHisto->fill( (sin(padTheta) - sin(mom.theta()))/sin(mom.theta()) );
658 
659  streamlog_out(DEBUG3) << "track Phi = " << trackPhi * (360.0 / twopi) << endl;
660  streamlog_out(DEBUG3) << "localPhi = " << localPhi * (360.0 / twopi) << endl;
661  streamlog_out(DEBUG3) << "pad Phi = " << padPhi * (360.0 / twopi) << endl;
662  streamlog_out(DEBUG3) << "pad Phi from track mom = " << ( thisPoint.phi() - trackPhi ) * (360.0 / twopi) << endl;
663  streamlog_out(DEBUG3) << "padTheta = " << padTheta * (360.0 / twopi) << endl;
664  streamlog_out(DEBUG3) << "padTheta from track mom = " << mom.theta() * (360.0 / twopi) << endl;
665 
666  }
667 #endif
668 
669  }
670 
671  // int pad = padLayout.getNearestPad(thisPoint.perp(),thisPoint.phi());
672  int layerNumber = _SimTHit->getCellID0();
673 
674  if(_rejectCellID0 && (layerNumber<1)) {
675  continue;
676  }
677 
678  edep = _SimTHit->getEDep();
679 
680  // Calculate Point Resolutions according to Ron's Formula
681 
682  // sigma_{RPhi}^2 = sigma_0^2 + Cd^2/N_{eff} * L_{drift}
683 
684  // sigma_0^2 = (50micron)^2 + (900micron*sin(phi))^2
685  // Cd^2/N_{eff}} = 25^2/(22/sin(theta)*h/6mm)
686  // Cd = 25 ( microns / cm^(1/2) )
687  // (this is for B=4T, h is the pad height = pad-row pitch in mm,
688  // theta is the polar angle)
689 
690  // sigma_{z}^2 = (400microns)^2 + L_{drift}cm * (80micron/sqrt(cm))^2
691 
692  double aReso =_pointResoRPhi0*_pointResoRPhi0 + (_pointResoPadPhi*_pointResoPadPhi * sin(padPhi)*sin(padPhi)) ;
693  double driftLength = gearTPC.getMaxDriftLength() - (fabs(thisPoint.z()));
694 
695  if (driftLength <0) {
696  streamlog_out(DEBUG3) << " TPCDigiProcessor : Warning! driftLength < 0 " << driftLength << " --> Check out your GEAR file!!!!" << std::endl;
697  streamlog_out(DEBUG3) << "Setting driftLength to 0.1" << std::endl;
698  streamlog_out(DEBUG3) << "gearTPC.getMaxDriftLength() = " << gearTPC.getMaxDriftLength() << std::endl;
699  driftLength = 0.10;
700  }
701 
702  padheight = padLayout.getPadHeight(padLayout.getNearestPad(thisPoint.perp(),thisPoint.phi()));
703 
704  // updated according to Dimitra Tsionou's instructions (D.Jeans 4 July 17)
705  // double bReso = ( (_diffRPhi * _diffRPhi) / _nEff ) * sin(padTheta) * ( 6.0 / (padheight) ) * ( 4.0 / bField ) ;
706  double bReso = ( (_diffRPhi * _diffRPhi) / _nEff ) * sin(padTheta) * ( 6.0 / (padheight) ) * ( (4.0 * 4.0) / (bField * bField) ) ;
707 
708  double tpcRPhiRes = sqrt( aReso + bReso * (driftLength / 10.0) ); // driftLength in cm
709 
710  double tpcZRes = sqrt(( _pointResoZ0 * _pointResoZ0 )
711  +
712  ( _diffZ * _diffZ ) * (driftLength / 10.0) ); // driftLength in cm
713 
714  int padIndex = padLayout.getNearestPad(thisPoint.perp(),thisPoint.phi());
715 
716  const gear::DoubleVec & planeExt = padLayout.getPlaneExtent() ;
717  double TPCPadPlaneRMin = planeExt[0] ;
718  double TPCPadPlaneRMax = planeExt[1] ;
719 
720  int iRowHit = padLayout.getRowNumber(padIndex);
721  int iPhiHit = padLayout.getPadNumber(padIndex);
722  int NBinsZ = (int) ((2.0 * gearTPC.getMaxDriftLength()) / _binningZ);
723  int iZHit = (int) ( (float) NBinsZ * ( gearTPC.getMaxDriftLength() + thisPoint.z() ) / ( 2.0 * gearTPC.getMaxDriftLength() ) ) ;
724 
725  if(iZHit<0) iZHit=0;
726  if(iZHit>NBinsZ) iZHit=NBinsZ;
727 
728  // make sure that the hit lies at the middle of the pad ring
729  thisPoint.setPerp(padLayout.getPadCenter(padIndex)[0]);
730 
731  if( (thisPoint.perp() < TPCPadPlaneRMin) || (thisPoint.perp() > TPCPadPlaneRMax) ) {
732  streamlog_out(DEBUG3) << "Hit R not in TPC " << endl;
733  streamlog_out(DEBUG3) << "R = " << thisPoint.perp() << endl;
734  streamlog_out(DEBUG3) << "the tpc InnerRadius = " << TPCPadPlaneRMin << endl;
735  streamlog_out(DEBUG3) << "the tpc OuterRadius = " << TPCPadPlaneRMax << endl;
736  streamlog_out(DEBUG3) << "Hit Dropped " << endl;
737  continue;
738  }
739 
740  if( (fabs(thisPoint.z()) > gearTPC.getMaxDriftLength()) ) {
741  streamlog_out(DEBUG3) << "Hit Z not in TPC " << endl;
742  streamlog_out(DEBUG3) << "Z = " << thisPoint.z() << endl;
743  streamlog_out(DEBUG3) << "the tpc Max Z = " << gearTPC.getMaxDriftLength() << endl;
744  streamlog_out(DEBUG3) << "Hit Dropped " << endl;
745  continue;
746  }
747 
748  //get energy deposit of this row
749  edep=_SimTHit->getEDep();
750 
751  // create a tpc voxel hit and store it for this row
752  Voxel_tpc * atpcVoxel = new Voxel_tpc(iRowHit,iPhiHit,iZHit, thisPoint, edep, tpcRPhiRes, tpcZRes);
753 
754  _tpcRowHits.at(iRowHit).push_back(atpcVoxel);
755  ++numberOfVoxelsCreated;
756 
757  // store the simhit pointer for this tpcvoxel hit in the hit map
758  _tpcHitMap[atpcVoxel] = _SimTHit;
759 
760  // move the pointers on
762  _previousMCP = _mcp ;
765 
766  }
767  }
768 
769  // now process the LowPt collection
770  LCCollection* STHcolLowPt = 0 ;
771  try{
772  STHcolLowPt = evt->getCollection( _lowPtHitscolName ) ;
773  }
774  catch(DataNotAvailableException &e){
775  }
776 
777  if(STHcolLowPt!=NULL){
778 
779  int n_sim_hitsLowPt = STHcolLowPt->getNumberOfElements() ;
780 
781  _NBackgroundSimTPCHits += n_sim_hitsLowPt;
782  _NSimTPCHits += n_sim_hitsLowPt;
783 
784  _padWidth = padLayout.getPadWidth(0)*padCoord[0];
785 
786  streamlog_out(DEBUG4) << "number of LowPt hits:" << n_sim_hitsLowPt << std::endl;
787 
788  // loop over the LowPt hit collection
789  for(int i=0; i< n_sim_hitsLowPt; i++){
790 
791  _SimTHit = dynamic_cast<SimTrackerHit*>( STHcolLowPt->getElementAt( i ) ) ;
792 
793  CLHEP::Hep3Vector thisPoint(_SimTHit->getPosition()[0],_SimTHit->getPosition()[1],_SimTHit->getPosition()[2]);
794 
795  const gear::DoubleVec & planeExt = padLayout.getPlaneExtent() ;
796  double TPCPadPlaneRMin = planeExt[0] ;
797  double TPCPadPlaneRMax = planeExt[1] ;
798 
799  int NBinsZ = (int) ((2.0 * gearTPC.getMaxDriftLength()) / _binningZ);
800 
801  if( (thisPoint.perp() < TPCPadPlaneRMin) || (thisPoint.perp() > TPCPadPlaneRMax) ) {
802  streamlog_out(DEBUG3) << "Hit R not in TPC " << endl;
803  streamlog_out(DEBUG3) << "R = " << thisPoint.perp() << endl;
804  streamlog_out(DEBUG3) << "the tpc InnerRadius = " << TPCPadPlaneRMin << endl;
805  streamlog_out(DEBUG3) << "the tpc OuterRadius = " << TPCPadPlaneRMax << endl;
806  streamlog_out(DEBUG3) << "Hit Dropped " << endl;
807  continue;
808  }
809 
810  if( (fabs(thisPoint.z()) > gearTPC.getMaxDriftLength()) ) {
811  streamlog_out(DEBUG3) << "Hit Z not in TPC " << endl;
812  streamlog_out(DEBUG3) << "Z = " << thisPoint.z() << endl;
813  streamlog_out(DEBUG3) << "the tpc Max Z = " << gearTPC.getMaxDriftLength() << endl;
814  streamlog_out(DEBUG3) << "Hit Dropped " << endl;
815  continue;
816  }
817 
818  int padIndex = padLayout.getNearestPad(thisPoint.perp(),thisPoint.phi());
819  //double padheight = padLayout.getPadHeight(padIndex);
820 
821  int iRowHit = padLayout.getRowNumber(padIndex);
822  int iPhiHit = padLayout.getPadNumber(padIndex);
823  int iZHit = (int) ( (float) NBinsZ *
824  ( gearTPC.getMaxDriftLength() + thisPoint.z() ) / ( 2.0 * gearTPC.getMaxDriftLength() ) ) ;
825 
826  // shift the hit in r-phi to the nearest pad-row centre
827  thisPoint.setPerp(padLayout.getPadCenter(padIndex)[0]);
828 
829  // set the resolutions to the pads to digital like values
830  double tpcRPhiRes = _padWidth;
831  double tpcZRes = _binningZ;
832 
833  //get energy deposit of this hit
834  edep=_SimTHit->getEDep();
835 
836  // create a tpc voxel hit for this simhit and store it for this tpc pad row
837  Voxel_tpc * atpcVoxel = new Voxel_tpc(iRowHit,iPhiHit,iZHit, thisPoint, edep, tpcRPhiRes, tpcZRes);
838 
839  _tpcRowHits.at(iRowHit).push_back(atpcVoxel);
840  ++numberOfVoxelsCreated;
841 
842  // store the simhit pointer for this voxel hit in a map
843  _tpcHitMap[atpcVoxel] = _SimTHit;
844 
845  }
846  }
847 
848  int number_of_adjacent_hits(0);
849 
850  streamlog_out(DEBUG4) << "finished looping over simhits, number of voxels = " << numberOfVoxelsCreated << endl;
851 
852  int numberOfhitsTreated(0);
853 
854  vector <Voxel_tpc *> row_hits;
855 
856  // loop over the tpc rows containing hits and check for merged hits
857  for (unsigned int i = 0; i<_tpcRowHits.size(); ++i){
858 
859  row_hits = _tpcRowHits.at(i);
860  std::sort(row_hits.begin(), row_hits.end(), compare_phi );
861 
862  // double loop over the hits in this row
863  for (unsigned int j = 0; j<row_hits.size(); ++j){
864 
865  ++numberOfhitsTreated;
866 
867  for (unsigned int k = j+1; k<row_hits.size(); ++k){
868 
869  if(row_hits[k]->getPhiIndex() > (row_hits[j]->getPhiIndex())+2){ // SJA:FIXME: here we need an OR to catch the wrap around
870  break; // only compare hits in adjacent phi bins
871  }
872 
873  // look to see if the two hit occupy the same pad in phi or if not whether they are within the r-phi double hit resolution
874  else if( row_hits[k]->getPhiIndex()==row_hits[j]->getPhiIndex()
875  ||
876  ( (fabs(row_hits[k]->getHep3Vector().deltaPhi(row_hits[j]->getHep3Vector()))) * row_hits[j]->getR()) < _doubleHitResRPhi ) {
877 
878  // if neighboring in phi then compare z
879  map <Voxel_tpc*,SimTrackerHit*> ::iterator it;
880 
881  SimTrackerHit* Hit1 = NULL;
882  SimTrackerHit* Hit2 = NULL;
883 
884  // search of the simhit pointers in the tpchit map
885  it=_tpcHitMap.find(row_hits[j]);
886  if(it!= _tpcHitMap.end()) {
887  Hit1 = it->second ; // hit found
888  }
889 
890  it=_tpcHitMap.find(row_hits[k]);
891  if(it!= _tpcHitMap.end()) {
892  Hit2 = it->second ; // hit found
893  }
894 
895  double pathlengthZ1(0.0);
896  double pathlengthZ2(0.0);
897 
898  if( Hit1 && Hit2 ){ // if both sim hits were found
899 
900  // check if the track momentum has been stored for the hits
901  bool momentum_set = true;
902 
903  if( STHcol != NULL ){
904  LCFlagImpl colFlag( STHcol->getFlag() ) ;
905  momentum_set = momentum_set && colFlag.bitSet(LCIO::THBIT_MOMENTUM) ;
906  }
907 
908  if( STHcolLowPt != NULL ){
909  LCFlagImpl colFlag( STHcolLowPt->getFlag() ) ;
910  momentum_set = momentum_set && colFlag.bitSet(LCIO::THBIT_MOMENTUM) ;
911  }
912 
913  if( momentum_set ){
914 
915  const float * Momentum1 = Hit1->getMomentum() ;
916  const float * Momentum2 = Hit2->getMomentum() ;
917 
918  CLHEP::Hep3Vector mom1(Momentum1[0],Momentum1[1],Momentum1[2]);
919  CLHEP::Hep3Vector mom2(Momentum2[0],Momentum2[1],Momentum2[2]);
920 
921  pathlengthZ1 = fabs( Hit1->getPathLength() * mom1.cosTheta() );
922  pathlengthZ2 = fabs( Hit2->getPathLength() * mom2.cosTheta() );
923  }
924  else {
925  pathlengthZ1 = _doubleHitResZ ; // assume the worst i.e. that the track is moving in z
926  pathlengthZ2 = _doubleHitResZ ; // assume the worst i.e. that the track is moving in z
927  }
928 
929  double dZ = fabs(row_hits[j]->getZ() - row_hits[k]->getZ());
930 
931  double spacial_coverage = 0.5*(pathlengthZ1 + pathlengthZ2) + _binningZ;
932 
933  if( (dZ - spacial_coverage) < _doubleHitResZ ){
934 
935  row_hits[j]->setAdjacent(row_hits[k]);
936  row_hits[k]->setAdjacent(row_hits[j]);
937  ++number_of_adjacent_hits;
938 
939  }
940  } else {
941  streamlog_out(DEBUG3) << "Hit1=" << Hit1 << "Hit2=" << Hit2 << endl;
942  }
943  }
944  }
945  }
946 
947 
948  // now all hits have been checked for adjacent hits, go throught and write out the hits or merge
949 
950  for (unsigned int j = 0; j<row_hits.size(); ++j){
951 
952  Voxel_tpc* seed_hit = row_hits[j];
953 
954  if(seed_hit->IsMerged() || seed_hit->IsClusterHit()) {
955  continue;
956  }
957 
958  if(seed_hit->getNumberOfAdjacent()==0){ // no adjacent hits so smear and write to hit collection
959  writeVoxelToHit(seed_hit);
960  }
961 
962  else if(seed_hit->getNumberOfAdjacent() < (_maxMerge)){ // potential 3-hit cluster, can use simple average merge.
963 
964  vector <Voxel_tpc*>* hitsToMerge = new vector <Voxel_tpc*>;
965 
966  int clusterSize = seed_hit->clusterFind(hitsToMerge);
967 
968  if( clusterSize <= _maxMerge ){ // merge cluster
969  seed_hit->setIsMerged();
970  writeMergedVoxelsToHit(hitsToMerge);
971  }
972  delete hitsToMerge;
973  }
974  }
975  }
976 
977  int numberOfHits(0);
978  // count up the number of hits merged or lost
979  for (unsigned int i = 0; i<_tpcRowHits.size(); ++i){
980  row_hits = _tpcRowHits.at(i);
981  for (unsigned int j = 0; j<row_hits.size(); ++j){
982  numberOfHits++;
983  Voxel_tpc* seed_hit = row_hits[j];
984  if(seed_hit->IsMerged() || seed_hit->IsClusterHit() || seed_hit->getNumberOfAdjacent() > _maxMerge ) {
985  ++_NRevomedHits;
986  _mcp = (_tpcHitMap[ seed_hit ])->getMCParticle() ;
987  if(_mcp != NULL ) {
989  const double *mom= _mcp->getMomentum() ;
990  double ptSQRD = mom[0]*mom[0]+mom[1]*mom[1] ;
991  if( ptSQRD > (0.2*0.2) ) ++_NLostPhysicsAbove02GeVPtTPCHits ;
992  if( ptSQRD > 1.0 ) ++_NLostPhysicsAbove1GeVPtTPCHits ;
993  }
994  }
995  }
996  }
997 
998  streamlog_out(DEBUG4) << "the number of adjacent hits is " << number_of_adjacent_hits << " _doubleHitResZ " << _doubleHitResZ << endl;
999  streamlog_out(DEBUG4) << "number of rec_hits = " << _NRecTPCHits << endl ;
1000  streamlog_out(DEBUG4) << "finished row hits " << numberOfHits << " " << numberOfhitsTreated << endl;
1001 
1002  // set the parameters to decode the type information in the collection
1003  // for the time being this has to be done manually
1004  // in the future we should provide a more convenient mechanism to
1005  // decode this sort of meta information
1006 
1007  StringVec typeNames ;
1008  IntVec typeValues ;
1009  typeNames.push_back( LCIO::TPCHIT ) ;
1010  typeValues.push_back( 1 ) ;
1011  _trkhitVec->parameters().setValues("TrackerHitTypeNames" , typeNames ) ;
1012  _trkhitVec->parameters().setValues("TrackerHitTypeValues" , typeValues ) ;
1013 
1014  // add the collection to the event
1015  evt->addCollection( _trkhitVec , _TPCTrackerHitsCol ) ;
1016  evt->addCollection( _relCol , _outRelColName ) ;
1017 
1018  // delete voxels
1019  for (unsigned int i = 0; i<_tpcRowHits.size(); ++i){
1020  vector <Voxel_tpc *>* current_row = &_tpcRowHits.at(i);
1021  for (unsigned int j = 0; j<current_row->size(); ++j){
1022  delete current_row->at(j);
1023  }
1024  }
1025 
1026 #ifdef DIGIPLOTS
1027  _NSimTPCHitsHisto->fill(_NSimTPCHits);
1028  _NBackgroundSimTPCHitsHisto->fill(_NBackgroundSimTPCHits);
1029  _NPhysicsSimTPCHitsHisto->fill(_NPhysicsSimTPCHits);
1030  _NPhysicsAbove02GeVSimTPCHitsHisto->fill(_NPhysicsAbove02GeVSimTPCHits);
1031  _NPhysicsAbove1GeVSimTPCHitsHisto->fill(_NPhysicsAbove1GeVSimTPCHits);
1032  _NRecTPCHitsHisto->fill(_NRecTPCHits);
1033 
1034  _NLostPhysicsTPCHitsHisto->fill(_NLostPhysicsTPCHits);
1035  _NLostPhysicsAbove02GeVPtTPCHitsHisto->fill(_NLostPhysicsAbove02GeVPtTPCHits);
1036  _NLostPhysicsAbove1GeVPtTPCHitsHisto->fill(_NLostPhysicsAbove1GeVPtTPCHits);
1037  _NRevomedHitsHisto->fill(_NRevomedHits);
1038 
1039  _NKeptPhysicsTPCHitsHistoPercent->fill( (float)(_NPhysicsSimTPCHits-_NLostPhysicsTPCHits) / (float)_NPhysicsSimTPCHits );
1040  _NKeptPhysicsAbove02GeVPtTPCHitsHistoPercent->fill( (float)(_NPhysicsAbove02GeVSimTPCHits-_NLostPhysicsAbove02GeVPtTPCHits) / (float)_NPhysicsAbove02GeVSimTPCHits );
1041  _NKeptPhysicsAbove1GeVPtTPCHitsHistoPercent->fill( (float)(_NPhysicsAbove1GeVSimTPCHits-_NLostPhysicsAbove1GeVPtTPCHits) / (float)_NPhysicsAbove1GeVSimTPCHits );
1042 #endif
1043 
1044  streamlog_out(DEBUG4) << "_NSimTPCHits = " << _NSimTPCHits << endl;
1045  streamlog_out(DEBUG4) << "_NBackgroundSimTPCHits = " << _NBackgroundSimTPCHits << endl;
1046  streamlog_out(DEBUG4) << "_NPhysicsSimTPCHits = " << _NPhysicsSimTPCHits << endl;
1047  streamlog_out(DEBUG4) << "_NPhysicsAbove02GeVSimTPCHits = " << _NPhysicsAbove02GeVSimTPCHits << endl;
1048  streamlog_out(DEBUG4) << "_NPhysicsAbove1GeVSimTPCHits = " << _NPhysicsAbove1GeVSimTPCHits << endl;
1049  streamlog_out(DEBUG4) << "_NRecTPCHits = " << _NRecTPCHits<< endl;
1050  streamlog_out(DEBUG4) << "_NLostPhysicsTPCHits = " << _NLostPhysicsTPCHits << endl;
1051  streamlog_out(DEBUG4) << "_NLostPhysicsAbove02GeVPtTPCHits = " << _NLostPhysicsAbove02GeVPtTPCHits << endl;
1052  streamlog_out(DEBUG4) << "_NLostPhysicsAbove1GeVPtTPCHits = " << _NLostPhysicsAbove1GeVPtTPCHits << endl;
1053  streamlog_out(DEBUG4) << "_NRevomedHits = " << _NRevomedHits << endl;
1054 
1055  _nEvt++;
1056  //Clear the maps and the end of the event.
1057  _tpcHitMap.clear();
1058  _tpcRowHits.clear();
1059 
1060  delete _cellid_encoder ;
1061 
1062 }
1063 
1064 
1065 
1066 void TPCDigiProcessor::check( LCEvent * /*evt*/ )
1067 {
1068  // nothing to check here - could be used to fill checkplots in reconstruction processor
1069 }
1070 
1071 
1073 {
1074 
1075 #ifdef DIGIPLOTS
1076  _TREE->commit();
1077  _TREE->cd("/Histograms");
1078  _TREE->ls("..");
1079 
1080  _TREE->close();
1081  streamlog_out(MESSAGE) << "DIGICHECKPLOTS Finished" << endl;
1082 #endif
1083 
1084  gsl_rng_free(_random);
1085  streamlog_out(MESSAGE) << "TPCDigiProcessor::end() " << name()
1086  << " processed " << _nEvt << " events in " << _nRun << " runs "
1087  << endl ;
1088  //
1089 }
1090 
1092 
1093  const gear::TPCParameters& gearTPC = Global::GEAR->getTPCParameters() ;
1094  const gear::PadRowLayout2D& padLayout = gearTPC.getPadLayout() ;
1095  const gear::Vector2D padCoord = padLayout.getPadCenter(1) ;
1096 
1097  Voxel_tpc* seed_hit = aVoxel;
1098 
1099  // if( seed_hit->getRowIndex() > 5 ) return ;
1100 
1101  //store hit variables
1102  TrackerHitImpl* trkHit = new TrackerHitImpl ;
1103  //now the hit pos has to be smeared
1104 
1105  double tpcRPhiRes = seed_hit->getRPhiRes();
1106  double tpcZRes = seed_hit->getZRes();
1107 
1108  CLHEP::Hep3Vector point(seed_hit->getX(),seed_hit->getY(),seed_hit->getZ());
1109 
1110  double unsmearedPhi = point.phi();
1111 
1112  double randrp = gsl_ran_gaussian(_random,tpcRPhiRes);
1113  double randz = gsl_ran_gaussian(_random,tpcZRes);
1114 
1115  point.setPhi( point.phi() + randrp/ point.perp() );
1116  point.setZ( point.z() + randz );
1117 
1118  // make sure the hit is not smeared beyond the TPC Max DriftLength
1119  if( fabs(point.z()) > gearTPC.getMaxDriftLength() ) point.setZ( (fabs(point.z()) / point.z() ) * gearTPC.getMaxDriftLength() );
1120 
1121  double pos[3] = {point.x(),point.y(),point.z()};
1122  trkHit->setPosition(pos);
1123  trkHit->setEDep(seed_hit->getEDep());
1124  // trkHit->setType( 500 );
1125 
1126 // int side = lcio::ILDDetID::barrel ;
1127 //
1128 // if( pos[2] < 0.0 ) side = 1 ;
1129 
1130  (*_cellid_encoder)[ lcio::LCTrackerCellID::subdet() ] = lcio::ILDDetID::TPC ;
1131  (*_cellid_encoder)[ lcio::LCTrackerCellID::layer() ] = seed_hit->getRowIndex() ;
1132  (*_cellid_encoder)[ lcio::LCTrackerCellID::module() ] = 0 ;
1133 
1134 
1135  //fg: optionally encode the side (should become the default eventually)
1136  if( ! _dontEncodeSide )
1137  (*_cellid_encoder)[ lcio::LCTrackerCellID::side() ] = ( pos[2] < 0 ? -1 : 1 ) ;
1138  else
1139  (*_cellid_encoder)[ lcio::LCTrackerCellID::side() ] = lcio::ILDDetID::barrel ;
1140 
1141  _cellid_encoder->setCellID( trkHit ) ;
1142 
1143 
1144  // check values for inf and nan
1145  if( std::isnan(unsmearedPhi) || std::isinf(unsmearedPhi) || std::isnan(tpcRPhiRes) || std::isinf(tpcRPhiRes) ) {
1146  std::stringstream errorMsg;
1147  errorMsg << "\nProcessor: TPCDigiProcessor \n"
1148  << "unsmearedPhi = "
1149  << unsmearedPhi
1150  << " tpcRPhiRes = "
1151  << tpcRPhiRes
1152  << "\n" ;
1153  throw Exception(errorMsg.str());
1154  }
1155 
1156  // For no error in R
1157  float covMat[TRKHITNCOVMATRIX]={float(sin(unsmearedPhi)*sin(unsmearedPhi)*tpcRPhiRes*tpcRPhiRes),
1158  float(-cos(unsmearedPhi)*sin(unsmearedPhi)*tpcRPhiRes*tpcRPhiRes),
1159  float(cos(unsmearedPhi)*cos(unsmearedPhi)*tpcRPhiRes*tpcRPhiRes),
1160  float(0.),
1161  float(0.),
1162  float(tpcZRes*tpcZRes) };
1163 
1164  trkHit->setCovMatrix(covMat);
1165 
1166  if( _tpcHitMap[seed_hit] == NULL ){
1167  std::stringstream errorMsg;
1168  errorMsg << "\nProcessor: TPCDigiProcessor \n"
1169  << "SimTracker Pointer is NULL throwing exception\n"
1170  << "\n" ;
1171  throw Exception(errorMsg.str());
1172  }
1173 
1174  if(pos[0]*pos[0]+pos[1]*pos[1]>0.0){
1175  // push back the SimTHit for this TrackerHit
1176 
1178  trkHit->rawHits().push_back( _tpcHitMap[seed_hit] );
1179  }
1180 
1181  LCRelationImpl* rel = new LCRelationImpl;
1182 
1183  rel->setFrom (trkHit);
1184  rel->setTo (_tpcHitMap[seed_hit]);
1185  rel->setWeight( 1.0 );
1186  _relCol->addElement(rel);
1187 
1188  _trkhitVec->addElement( trkHit );
1189  _NRecTPCHits++;
1190  }
1191 
1192 
1193 #ifdef DIGIPLOTS
1194  SimTrackerHit* theSimHit = _tpcHitMap[seed_hit];
1195  double rSimSqrd = theSimHit->getPosition()[0]*theSimHit->getPosition()[0] + theSimHit->getPosition()[1]*theSimHit->getPosition()[1];
1196 
1197  double phiSim = atan2(theSimHit->getPosition()[1],theSimHit->getPosition()[0]);
1198 
1199  double rPhiDiff = (point.phi() - phiSim)*sqrt(rSimSqrd);
1200  double rPhiPull = ((point.phi() - phiSim)*sqrt(rSimSqrd))/(sqrt((covMat[2])/(cos(point.phi())*cos(point.phi()))));
1201 
1202  double zDiff = point.getZ() - theSimHit->getPosition()[2];
1203  double zPull = zDiff/sqrt(covMat[5]);
1204 
1205 
1206  _rPhiDiffHisto->fill(rPhiDiff);
1207  _rPhiPullHisto->fill(rPhiPull);
1208  _phiDistHisto->fill(point.phi() - phiSim);
1209  _zDiffHisto->fill(zDiff);
1210  _zPullHisto->fill(zPull);
1211 
1212  _zSigmaVsZHisto->fill(seed_hit->getZ(),sqrt(covMat[5]));
1213  _rPhiSigmaHisto->fill(sqrt((covMat[2])/(cos(point.phi())*cos(point.phi()))));
1214  _zSigmaHisto->fill(sqrt(covMat[5]));
1215 #endif
1216 }
1217 
1218 void TPCDigiProcessor::writeMergedVoxelsToHit( vector <Voxel_tpc*>* hitsToMerge){
1219 
1220  const gear::TPCParameters& gearTPC = Global::GEAR->getTPCParameters() ;
1221  const gear::PadRowLayout2D& padLayout = gearTPC.getPadLayout() ;
1222  const gear::Vector2D padCoord = padLayout.getPadCenter(1) ;
1223 
1224  TrackerHitImpl* trkHit = new TrackerHitImpl ;
1225 
1226  double sumZ = 0;
1227  double sumPhi = 0;
1228  double sumEDep = 0;
1229  // double R = 0;
1230  double lastR = 0;
1231 
1232  unsigned number_of_hits_to_merge = hitsToMerge->size();
1233 
1234 
1235  for(unsigned int ihitCluster = 0; ihitCluster < number_of_hits_to_merge; ++ihitCluster){
1236 
1237  sumZ += hitsToMerge->at(ihitCluster)->getZ();
1238  sumPhi += hitsToMerge->at(ihitCluster)->getPhi();
1239  sumEDep += hitsToMerge->at(ihitCluster)->getEDep();
1240  hitsToMerge->at(ihitCluster)->setIsMerged();
1241  lastR = hitsToMerge->at(ihitCluster)->getR();
1242 
1244  trkHit->rawHits().push_back( _tpcHitMap[hitsToMerge->at(ihitCluster)] );
1245  }
1246 
1247  LCRelationImpl* rel = new LCRelationImpl;
1248 
1249  rel->setFrom (trkHit);
1250  rel->setTo (_tpcHitMap[ hitsToMerge->at(ihitCluster) ]);
1251  rel->setWeight( float(1.0/number_of_hits_to_merge) );
1252  _relCol->addElement(rel);
1253 
1254  }
1255 
1256  double avgZ = sumZ/(hitsToMerge->size());
1257  double avgPhi = sumPhi/(hitsToMerge->size());
1258 
1259  //set deposit energy as mean of merged hits
1260  sumEDep=sumEDep/(double)number_of_hits_to_merge;
1261 
1262  CLHEP::Hep3Vector* mergedPoint = new CLHEP::Hep3Vector(1.0,1.0,1.0);
1263  mergedPoint->setPerp(lastR);
1264  mergedPoint->setPhi(avgPhi);
1265  mergedPoint->setZ(avgZ);
1266 
1267  //store hit variables
1268 
1269  // first the hit pos has to be smeared------------------------------------------------
1270 
1271  //FIXME: which errors should we use for smearing the merged hits ?
1272  // this might be a bit large ....
1273  double tpcRPhiRes = _padWidth;
1274  double tpcZRes = _binningZ;
1275 
1276  CLHEP::Hep3Vector point( mergedPoint->getX(), mergedPoint->getY(), mergedPoint->getZ() ) ;
1277 
1278 // double unsmearedPhi = point.phi();
1279 
1280  double randrp = gsl_ran_gaussian(_random,tpcRPhiRes);
1281  double randz = gsl_ran_gaussian(_random,tpcZRes);
1282 
1283  point.setPhi( point.phi() + randrp/ point.perp() );
1284  point.setZ( point.z() + randz );
1285 
1286  // make sure the hit is not smeared beyond the TPC Max DriftLength
1287  if( fabs(point.z()) > gearTPC.getMaxDriftLength() ) point.setZ( (fabs(point.z()) / point.z() ) * gearTPC.getMaxDriftLength() );
1288 
1289  double pos[3] = {point.x(),point.y(),point.z()};
1290 
1291  //---------------------------------------------------------------------------------
1292  trkHit->setPosition(pos);
1293  trkHit->setEDep(sumEDep);
1294  // trkHit->setType( 500 );
1295 
1296  int padIndex = padLayout.getNearestPad(mergedPoint->perp(),mergedPoint->phi());
1297  int row = padLayout.getRowNumber(padIndex);
1298 
1299  (*_cellid_encoder)[ lcio::LCTrackerCellID::subdet() ] = lcio::ILDDetID::TPC ;
1300  (*_cellid_encoder)[ lcio::LCTrackerCellID::layer() ] = row ;
1301  (*_cellid_encoder)[ lcio::LCTrackerCellID::module() ] = 0 ;
1302 
1303  //fg: optionally encode the side (should become the default eventually)
1304  if( ! _dontEncodeSide )
1305  (*_cellid_encoder)[ lcio::LCTrackerCellID::side() ] = ( pos[2] < 0 ? -1 : 1 ) ;
1306  else
1307  (*_cellid_encoder)[ lcio::LCTrackerCellID::side() ] = lcio::ILDDetID::barrel ;
1308 
1309  _cellid_encoder->setCellID( trkHit ) ;
1310 
1311 
1312  double phi = mergedPoint->getPhi();
1313 
1314  // check values for inf and nan
1315  if( std::isnan(phi) || std::isinf(phi) || std::isnan(tpcRPhiRes) || std::isinf(tpcRPhiRes) ) {
1316  std::stringstream errorMsg;
1317  errorMsg << "\nProcessor: TPCDigiProcessor \n"
1318  << "phi = "
1319  << phi
1320  << " tpcRPhiRes = "
1321  << tpcRPhiRes
1322  << "\n" ;
1323  throw Exception(errorMsg.str());
1324  }
1325 
1326  // For no error in R
1327  float covMat[TRKHITNCOVMATRIX]={float(sin(phi)*sin(phi)*tpcRPhiRes*tpcRPhiRes),
1328  float(-cos(phi)*sin(phi)*tpcRPhiRes*tpcRPhiRes),
1329  float(cos(phi)*cos(phi)*tpcRPhiRes*tpcRPhiRes),
1330  float(0.),
1331  float(0.),
1332  float(tpcZRes*tpcZRes)};
1333 
1334  trkHit->setCovMatrix(covMat);
1335 
1336  // if(pos[0]*pos[0]+pos[1]*pos[1]>0.0){
1337  _trkhitVec->addElement( trkHit );
1338  ++_nRechits;
1339  // } else {
1340  // delete trkHit;
1341  // }
1342 
1343  delete mergedPoint;
1344 
1345 }
1346 
1347 
1348 #ifdef DIGIPLOTS
1349 void TPCDigiProcessor::plotHelixHitResidual( MCParticle *mcp, CLHEP::Hep3Vector *thisPoint){
1350 
1351  const double bField = Global::GEAR->getBField().at( gear::Vector3D( 0., 0., 0.) ).z() ;
1352  const double FCT = 2.99792458E-4;
1353  double charge = mcp->getCharge();
1354  const double *mom = mcp->getMomentum();
1355  double pt = sqrt(mom[0]*mom[0]+mom[1]*mom[1]);
1356  double radius = pt / (FCT*bField);
1357  double tanLambda = mom[2]/pt;
1358  double omega = charge / radius;
1359 
1360  if(pt>1.0) {
1361 
1362  //FIXME SJA: this is only valid for tracks from the IP and should be done correctly for non prompt tracks
1363  double Z0 = 0.;
1364  double D0 = 0.;
1365 
1366  LCVector3D refPoint(0.,0.,0);
1367 
1368  SimpleHelix* helix = new SimpleHelix(D0,
1369  atan2(mom[1],mom[0]),
1370  omega,
1371  Z0,
1372  tanLambda,
1373  refPoint);
1374 
1375 
1376  // an almost "infinite" cylinder in z
1377  LCVector3D startCylinder(0.,0.,-1000000.0);
1378  LCVector3D endCylinder(0.,0.,1000000.0);
1379  bool endplane=true;
1380 
1381  LCCylinder cylinder(startCylinder,endCylinder,thisPoint->perp(),endplane);
1382 
1383  bool pointExists = false;
1384 
1385  double pathlength = helix->getIntersectionWithCylinder( cylinder, pointExists);
1386 
1387  LCErrorMatrix* errors = new LCErrorMatrix();
1388 
1389  if(pointExists){
1390 
1391  LCVector3D intersection = helix->getPosition(pathlength, errors);
1392 
1393  double intersectionPhi = atan2(intersection[1],intersection[0]);
1394  double residualRPhi = ((intersectionPhi-thisPoint->phi())) ;
1395  _ResidualsRPhiHisto->fill(residualRPhi);
1396 
1397  }
1398 
1399  delete errors;
1400  delete helix;
1401 
1402  const gear::TPCParameters& gearTPC = Global::GEAR->getTPCParameters() ;
1403  const gear::PadRowLayout2D& padLayout = gearTPC.getPadLayout() ;
1404 
1405  int row = padLayout.getRowNumber(padLayout.getNearestPad(thisPoint->perp(),thisPoint->phi()));
1406  int pad = padLayout.getNearestPad(thisPoint->perp(),thisPoint->phi());
1407 
1408  double rHit_diff = thisPoint->perp()
1409  - padLayout.getPlaneExtent()[0]
1410  - (( row + 0.5 )
1411  * padLayout.getPadHeight(pad)) ;
1412 
1413  _radiusCheckHisto->fill(rHit_diff);
1414 
1415  // streamlog_out(MESSAGE) << "$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$" << endl;
1416  // streamlog_out(MESSAGE) << "thisPoint->perp() = " << thisPoint->perp() << endl;
1417  // streamlog_out(MESSAGE) << "TPC Sensitive rMin = " << padLayout.getPlaneExtent()[0] << endl;
1418  // streamlog_out(MESSAGE) << "Row number + 0.5 = " << row + 0.5 << endl;
1419  // streamlog_out(MESSAGE) << "Pad Height = " << padLayout.getPadHeight(pad) << endl;
1420  // streamlog_out(MESSAGE) << "Row Height = " << padLayout.getRowHeight(row) << endl;
1421  // streamlog_out(MESSAGE) << "R_hit - TPC Rmin - ((RowIndex + 0.5 )* padheight) = " << rHit_diff << endl;
1422 
1423  }
1424  return;
1425 }
1426 #endif
1427 
1428 
1429 double TPCDigiProcessor::getPadPhi( CLHEP::Hep3Vector *thisPoint, CLHEP::Hep3Vector* firstPoint, CLHEP::Hep3Vector* middlePoint, CLHEP::Hep3Vector* lastPoint){
1430 
1431  CLHEP::Hep2Vector firstPointRPhi(firstPoint->x(),firstPoint->y());
1432  CLHEP::Hep2Vector middlePointRPhi(middlePoint->x(),middlePoint->y());
1433  CLHEP::Hep2Vector lastPointRPhi(lastPoint->x(),lastPoint->y());
1434 
1435  // check that the points are not the same, at least at the level of a tenth of a micron
1436  if( (fabs( firstPointRPhi.x() - middlePointRPhi.x() ) < 1.e-05 && fabs( firstPointRPhi.y() - middlePointRPhi.y() ) < 1.e-05)
1437  ||
1438  (fabs( middlePointRPhi.x() - lastPointRPhi.x() ) < 1.e-05 && fabs( middlePointRPhi.y() - lastPointRPhi.y() ) < 1.e-05)
1439  ||
1440  (fabs( firstPointRPhi.x() - lastPointRPhi.x() ) < 1.e-05 && fabs( firstPointRPhi.y() - lastPointRPhi.y() ) < 1.e-05)
1441  ) {
1442 
1443  streamlog_out(WARNING) << " TPCDigiProcessor::getPadPhi "
1444  << "2 of the 3 SimTracker hits passed to Circle Fit are the same hit taking pad phi as PI/2\n"
1445  << " firstPoint->x() " << firstPoint->x()
1446  << " firstPoint->y() " << firstPoint->y()
1447  << " firstPoint->z() " << firstPoint->z()
1448  << " middlePoint->x() " << middlePoint->x()
1449  << " middlePoint->y() " << middlePoint->y()
1450  << " middlePoint->z() " << middlePoint->z()
1451  << " lastPoint->x() " << lastPoint->x()
1452  << " lastPoint->y() " << lastPoint->y()
1453  << " lastPoint.z() " << lastPoint->z()
1454  << std::endl ;
1455 
1456  return twopi/4.0 ;
1457 
1458  }
1459 
1460 
1461 
1462  Circle theCircle(&firstPointRPhi, &middlePointRPhi, &lastPointRPhi);
1463 
1464  double localPhi = atan2((thisPoint->y() - theCircle.GetCenter()->y()) ,(thisPoint->x() - theCircle.GetCenter()->x())) + (twopi/4.0) ;
1465 
1466  if(localPhi>twopi) localPhi=localPhi - twopi;
1467  if(localPhi<0.0) localPhi=localPhi + twopi;
1468  if(localPhi>twopi/2.0) localPhi = localPhi - twopi/2.0 ;
1469 
1470  double pointPhi = thisPoint->phi();
1471 
1472  if(pointPhi>twopi) pointPhi=pointPhi - twopi;
1473  if(pointPhi<0.0) pointPhi=pointPhi + twopi;
1474  if(pointPhi>twopi/2.0) pointPhi = pointPhi - twopi/2.0 ;
1475 
1476  double padPhi = fabs(pointPhi - localPhi);
1477 
1478  // check that the value returned is reasonable
1479  if( std::isnan(padPhi) || std::isinf(padPhi) ) {
1480  std::stringstream errorMsg;
1481  errorMsg << "\nProcessor: TPCDigiProcessor \n"
1482  << "padPhi = "
1483  << padPhi
1484  << "\n" ;
1485  throw Exception(errorMsg.str());
1486  }
1487 
1488  return padPhi;
1489 
1490 }
1491 
1492 double TPCDigiProcessor::getPadTheta(CLHEP::Hep3Vector* firstPoint, CLHEP::Hep3Vector* middlePoint, CLHEP::Hep3Vector* lastPoint){
1493 
1494  // Calculate thetaPad for current hit
1495  CLHEP::Hep2Vector firstPointRPhi(firstPoint->x(),firstPoint->y()) ;
1496  CLHEP::Hep2Vector middlePointRPhi(middlePoint->x(),middlePoint->y());
1497  CLHEP::Hep2Vector lastPointRPhi(lastPoint->x(),lastPoint->y());
1498 
1499  // check that the points are not the same, at least at the level of a tenth of a micron
1500  if( (fabs( firstPointRPhi.x() - middlePointRPhi.x() ) < 1.e-05 && fabs( firstPointRPhi.y() - middlePointRPhi.y() ) < 1.e-05)
1501  ||
1502  (fabs( middlePointRPhi.x() - lastPointRPhi.x() ) < 1.e-05 && fabs( middlePointRPhi.y() - lastPointRPhi.y() ) < 1.e-05)
1503  ||
1504  (fabs( firstPointRPhi.x() - lastPointRPhi.x() ) < 1.e-05 && fabs( firstPointRPhi.y() - lastPointRPhi.y() ) < 1.e-05)
1505  ) {
1506 
1507  streamlog_out(WARNING) << " TPCDigiProcessor::getPadTheta "
1508  << "2 of the 3 SimTracker hits passed to Circle Fit are the same hit taking pad phi as PI/2\n"
1509  << " firstPoint->x() " << firstPoint->x()
1510  << " firstPoint->y() " << firstPoint->y()
1511  << " firstPoint->z() " << firstPoint->z()
1512  << " middlePoint->x() " << middlePoint->x()
1513  << " middlePoint->y() " << middlePoint->y()
1514  << " middlePoint->z() " << middlePoint->z()
1515  << " lastPoint->x() " << lastPoint->x()
1516  << " lastPoint->y() " << lastPoint->y()
1517  << " lastPoint.z() " << lastPoint->z()
1518  << std::endl ;
1519 
1520  return twopi/4.0 ;
1521 
1522  }
1523 
1524 
1525  Circle theCircle(&firstPointRPhi, &middlePointRPhi, &lastPointRPhi);
1526 
1527  double deltaPhi = firstPoint->deltaPhi(*lastPoint);
1528 
1529  double pathlength = fabs(deltaPhi) * theCircle.GetRadius();
1530 
1531  double padTheta = atan ( pathlength / fabs(lastPoint->z() - firstPoint->z()) ) ;
1532 
1533  double pathlength1 = 2.0 * asin( ( sqrt (
1534  (middlePointRPhi.x() - firstPointRPhi.x()) * (middlePointRPhi.x()-firstPointRPhi.x())
1535  +
1536  (middlePointRPhi.y()-firstPointRPhi.y()) * (middlePointRPhi.y()-firstPointRPhi.y())
1537  ) / 2.0 ) / theCircle.GetRadius() ) * theCircle.GetRadius() ;
1538 
1539 
1540  double pathlength2 = 2.0 * asin( ( sqrt (
1541  (lastPointRPhi.x()-middlePointRPhi.x()) * (lastPointRPhi.x()-middlePointRPhi.x())
1542  +
1543  (lastPointRPhi.y()-middlePointRPhi.y()) * (lastPointRPhi.y()-middlePointRPhi.y())
1544  ) / 2.0 ) / theCircle.GetRadius() ) * theCircle.GetRadius() ;
1545 
1546 
1547  padTheta = atan ((fabs(pathlength1 + pathlength2)) / (fabs(lastPoint->z() - firstPoint->z())) ) ;
1548 
1549  // check that the value returned is reasonable
1550  if( std::isnan(padTheta) || std::isinf(padTheta) ) {
1551  std::stringstream errorMsg;
1552  errorMsg << "\nProcessor: TPCDigiProcessor \n"
1553  << "padTheta = "
1554  << padTheta
1555  << "\n" ;
1556  throw Exception(errorMsg.str());
1557  }
1558 
1559  return padTheta;
1560 
1561 }
int getNumberOfAdjacent()
Definition: voxel.h:40
double getEDep()
Definition: voxel.h:46
double getX()
Definition: voxel.h:41
SimTrackerHit * _nMinus2SimHit
std::vector< double * > DoubleVec
Definition: SiStripClus.h:54
void writeMergedVoxelsToHit(std::vector< Voxel_tpc * > *hitList)
std::string _spacePointColName
virtual void init()
Called at the begin of the job before anything is read.
SimTrackerHit * _SimTHit
CLHEP::Hep3Vector Vector3D
bool compare_z(Voxel_tpc *a, Voxel_tpc *b)
double getPadTheta(CLHEP::Hep3Vector *firstPointRPhi, CLHEP::Hep3Vector *middlePointRPhi, CLHEP::Hep3Vector *lastPointRPhi)
SimTrackerHit * _previousSimTHit
static const float k
int getRowIndex()
Definition: voxel.h:35
CellIDEncoder< TrackerHitImpl > * _cellid_encoder
EVENT::MCParticle * _nPlus2MCP
virtual void end()
Called after data processing for clean up.
int getPhiIndex()
Definition: voxel.h:36
double getY()
Definition: voxel.h:42
double getPadPhi(CLHEP::Hep3Vector *thisPointRPhi, CLHEP::Hep3Vector *firstPointRPhi, CLHEP::Hep3Vector *middlePointRPhi, CLHEP::Hep3Vector *lastPointRPhi)
bool IsClusterHit()
Definition: voxel.h:30
EVENT::MCParticle * _nextMCP
int getZIndex()
Definition: voxel.h:37
bool _use_raw_hits_to_store_simhit_pointer
int clusterFind(vector< Voxel_tpc * > *hitList)
Definition: voxel.cc:48
double getZRes()
Definition: voxel.h:48
LCCollectionVec * _trkhitVec
void plotHelixHitResidual(MCParticle *mcp, CLHEP::Hep3Vector *thisPointRPhi)
SimTrackerHit * _nPlus2SimHit
void setIsMerged()
Definition: voxel.h:29
LCCollectionVec * _relCol
virtual void check(LCEvent *evt)
std::vector< std::vector< Voxel_tpc * > > _tpcRowHits
int _NLostPhysicsAbove02GeVPtTPCHits
const float twopi
Definition: ILDCaloDigi.cc:38
static const float e
MCParticle * getMCParticle(ReconstructedParticle *recPart, LCCollection *colMCTL)
Definition: Utilities.cc:30
bool compare_phi(Voxel_tpc *a, Voxel_tpc *b)
EVENT::MCParticle * _nMinus2MCP
std::vector< LCCollection * > LCCollectionVec
Definition: SiStripClus.h:55
bool IsMerged()
Definition: voxel.h:31
double getZ()
Definition: voxel.h:43
std::string _lowPtHitscolName
virtual void processRunHeader(LCRunHeader *run)
Called for every run.
virtual void processEvent(LCEvent *evt)
Called for every event - the working horse.
EVENT::MCParticle * _mcp
std::map< Voxel_tpc *, SimTrackerHit * > _tpcHitMap
SimTrackerHit * _nextSimTHit
std::string _outRelColName
void writeVoxelToHit(Voxel_tpc *aVoxel)
TPCDigiProcessor aTPCDigiProcessor
std::string _TPCTrackerHitsCol
Output collection name.
std::string _padRowHitColName
Input collection name.
double getRPhiRes()
Definition: voxel.h:47
EVENT::MCParticle * _previousMCP
std::vector< std::string > StringVec
Definition: SiStripClus.h:56