All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
BruteForceEcalGapFiller.cc
Go to the documentation of this file.
2 
3 #include <IMPL/CalorimeterHitImpl.h>
4 
5 #include <EVENT/LCCollection.h>
6 #include <EVENT/CalorimeterHit.h>
7 #include <UTIL/CellIDDecoder.h>
8 #include <CalorimeterHitType.h>
9 
10 #include "DD4hep/DetType.h"
11 
12 
13 #include <iostream>
14 using std::cout;
15 using std::endl;
16 
17 #include <cassert>
18 #include <math.h>
19 
20 #include "DD4hep/DetectorSelector.h"
21 #include "DD4hep/DetType.h"
22 #include "DD4hep/Detector.h"
23 
25 
26 BruteForceEcalGapFiller::BruteForceEcalGapFiller( ) : Processor( "BruteForceEcalGapFiller" ) {
27 
28  _description = "makes a collection of ECAL gap hits" ;
29 
30  // input collection of calohits
31  std::string inputCollection;
32  registerInputCollection( LCIO::CALORIMETERHIT,
33  "inputHitCollection" ,
34  "input simcalhit Collection Name" ,
36  inputCollection);
37 
38  std::string outputCollection;
39  registerOutputCollection(LCIO::CALORIMETERHIT,
40  "outputHitCollection",
41  "output calorimeterhit Collection Name" ,
43  outputCollection );
44 
45  registerProcessorParameter("CellIDLayerString" ,
46  "name of the part of the cellID that holds the layer" ,
48  std::string("layer")
49  );
50 
51  registerProcessorParameter("CellIDModuleString" ,
52  "name of the part of the cellID that holds the module" ,
54  std::string("module")
55  );
56 
57  registerProcessorParameter("CellIDStaveString" ,
58  "name of the part of the cellID that holds the stave" ,
60  std::string("stave")
61  );
62 
63  registerProcessorParameter("expectedInterModuleDistance",
64  "size of gap across module boundaries (from edge to edge of cells, in mm ; accuracy < cell size)",
66  float (7.)
67  );
68 
69  registerProcessorParameter("interModuleNonlinearFactor",
70  "nonlin factor f: E_corr = interModuleCorrectionFactor*(1/f)*log(1 + f*E_calc)",
72  float (1.) );
73 
74  registerProcessorParameter("intraModuleNonlinearFactor",
75  "nonlin factor f: E_corr = intraModuleCorrectionFactor*(1/f)*log(1 + f*E_calc)",
77  float (1.) );
78 
79  registerProcessorParameter("interModuleCorrectionFactor",
80  "factor applied to calculated energy of inter-module gap hits",
82  float (0.35) );
83 
84  registerProcessorParameter("intraModuleCorrectionFactor",
85  "factor applied to calculated energy of intra-module gap hits",
87  float (1.0) );
88 
89  registerProcessorParameter("applyInterModuleCorrection",
90  "apply correction for gaps between modules?",
92  bool(true) );
93 
94 }
95 
96 
98 
99  printParameters();
100 
101  _flag.setBit(LCIO::CHBIT_LONG);
102  _flag.setBit(LCIO::RCHBIT_TIME); //store timing on output hits.
103 
104  _currentLayout=-99;
105 
106 }
107 
108 
109 
111 
112  streamlog_out ( DEBUG1 ) << "looking for collection: " << _inputHitCollection << endl;
113  try{
114  LCCollection * col = evt->getCollection( _inputHitCollection.c_str() ) ;
115 
116  int numElements = col->getNumberOfElements();
117  streamlog_out ( DEBUG1 ) << _inputHitCollection << " number of elements = " << numElements << endl;
118 
119  if ( numElements>0 ) {
120 
121  CellIDDecoder<CalorimeterHit> idDecoder( col );
122 
123  for (int il=0; il<MAXLAYER; il++)
124  for (int is=0; is<MAXSTAVE; is++)
125  for (int im=0; im<MAXMODULE; im++)
126  hitsByLayerModuleStave[il][is][im].clear();
127 
128  // loop over input hits
129  for (int j(0); j < numElements; ++j) {
130  CalorimeterHit * hit = dynamic_cast<CalorimeterHit*>( col->getElementAt( j ) ) ;
131 
132  if (j==0) getGeometryData( hit->getType() ); // update geom info for first hit in collection (assumes that single collection doesn't mix endcap and barrel hits)
133 
134  int layer = idDecoder(hit)[_cellIDLayerString];
135  int stave = idDecoder(hit)[_cellIDStaveString];
136  int module = idDecoder(hit)[_cellIDModuleString];
137  assert( layer>=0 && layer<MAXLAYER );
138  assert( stave>=0 && stave<MAXSTAVE );
139  assert( module>=0 && module<MAXMODULE);
140  hitsByLayerModuleStave[layer][stave][module].push_back(hit);
141  }
142 
143  // now make the gap hits
144 
145  // create new collection: hits
146  std::string encodingString = col->getParameters().getStringVal(LCIO::CellIDEncoding);
147  LCCollectionVec *newcol = new LCCollectionVec(LCIO::CALORIMETERHIT);
148  newcol->parameters().setValue(LCIO::CellIDEncoding,encodingString);
149  newcol->setFlag(_flag.getFlag());
150 
151  addIntraModuleGapHits(newcol); // gaps within a module
152  if ( _applyInterModuleCor ) addInterModuleGapHits(newcol); // gaps between modules
153 
154  evt->addCollection( newcol, _outputHitCollection );
155 
156  }
157 
158  } catch(DataNotAvailableException &e){
159  streamlog_out(DEBUG1) << "could not find input collection " << _inputHitCollection << std::endl;
160  }
161 
162 
163 }
164 
166  // get information about geometry
167  // calorimeter hit type used to decide if it's in barrel or endcap
168 
169  CHT calHitType( ihitType );
170  if ( ! calHitType.is(CHT::ecal) ) {
171  streamlog_out (ERROR) << "this is not an ECAL hit!" << endl;
172  assert(0);
173  }
174 
175  int iLayout(-99);
176  if ( calHitType.is( CHT::barrel ) ) iLayout=ECALBARREL;
177  else if ( calHitType.is( CHT::endcap ) ) iLayout=ECALENDCAP;
178  else {
179  streamlog_out (ERROR) << "this hit is in neither barrel not endcap" << endl;
180  assert(0);
181  }
182 
183  if ( iLayout != _currentLayout ) { // layout (barrel/endcap region) has changed, get appropriate geom data
184  _currentLayout = iLayout;
185 
186  unsigned int includeFlag(0);
187  unsigned int excludeFlag(0);
188 
189  if ( calHitType.is( CHT::barrel ) ) {
190  includeFlag = ( dd4hep::DetType::CALORIMETER | dd4hep::DetType::ELECTROMAGNETIC | dd4hep::DetType::BARREL);
191  excludeFlag = ( dd4hep::DetType::AUXILIARY | dd4hep::DetType::FORWARD );
192  } else if ( calHitType.is( CHT::endcap ) ) {
193  includeFlag = ( dd4hep::DetType::CALORIMETER | dd4hep::DetType::ELECTROMAGNETIC | dd4hep::DetType::ENDCAP);
194  excludeFlag = ( dd4hep::DetType::AUXILIARY | dd4hep::DetType::FORWARD );
195  }
196 
197  dd4hep::Detector & lcdd = dd4hep::Detector::getInstance();
198  const std::vector< dd4hep::DetElement>& theDetectors = dd4hep::DetectorSelector(lcdd).detectors( includeFlag, excludeFlag ) ;
199  streamlog_out( DEBUG2 ) << " getExtension : includeFlag: " << dd4hep::DetType( includeFlag ) << " excludeFlag: " << dd4hep::DetType( excludeFlag )
200  << " found : " << theDetectors.size() << " - first det: " << theDetectors.at(0).name() << std::endl ;
201 
202  if( theDetectors.size() != 1 ){
203  std::stringstream es ;
204  streamlog_out (ERROR) << " getExtension: selection is not unique (or empty) includeFlag: " << dd4hep::DetType( includeFlag ) << " excludeFlag: " << dd4hep::DetType( excludeFlag )
205  << " --- found detectors : " ;
206  for( unsigned i=0, N= theDetectors.size(); i<N ; ++i ){
207  streamlog_out (ERROR) << theDetectors.at(i).name() << ", " ;
208  }
209  assert(0);
210  }
211  _caloGeomData = theDetectors.at(0).extension<dd4hep::rec::LayeredCalorimeterData>();
212 
213  if ( ! _caloGeomData ) {
214  streamlog_out ( WARNING ) << "could not get calorimeter geometry information!" << endl;
215  assert(0);
216  }
217  }
218 
219  return;
220 }
221 
223  // look for gaps within modules
224  // i.e. between wafers, between towers
225 
226  streamlog_out ( DEBUG1 ) << " starting addIntraModuleGapHits" << endl;
227 
228 
229  const float verySmallDist = 0.01; // don't consider differences below this distance to be a gap
230  const float slop = 0.01; // flexibility, as ratio
231 
232  for (int il=0; il<MAXLAYER; il++) {
233 
234  // we have to get the cell sizes here
235  float cellsizeA, cellsizeB;
236  if (_currentLayout==ECALBARREL) {
237  cellsizeA = _caloGeomData->layers[il].cellSize0; // phi dir, in CM!!
238  cellsizeB = _caloGeomData->layers[il].cellSize1; // z dir
239  } else { // endcap - we should take care of the rotation with stave number if thse are different...
240  cellsizeA = _caloGeomData->layers[il].cellSize0; // x dir
241  cellsizeB = _caloGeomData->layers[il].cellSize1; // y dir
242  }
243  cellsizeA*=10;
244  cellsizeB*=10; // convert to mm
245 
246  streamlog_out ( DEBUG1 )<< "cell sizes in layer " << il << " = " << cellsizeA << " " << cellsizeB << endl;
247 
248  for (int is=0; is<MAXSTAVE; is++) {
249  for (int im=0; im<MAXMODULE; im++) {
250  std::vector < CalorimeterHit* > theseHits = hitsByLayerModuleStave[il][is][im];
251  if ( theseHits.size()>1 ) {
252  bool gap(false);
253  float enFrac(0);
254  for ( size_t ih=0; ih<theseHits.size()-1; ih++) {
255  for ( size_t jh=ih+1; jh<theseHits.size(); jh++) {
256  float dist1d[3];
257  for (int i=0; i<3; i++)
258  dist1d[i] = fabs( theseHits[ih]->getPosition()[i] - theseHits[jh]->getPosition()[i] );
259  float distXY = sqrt( pow( dist1d[0], 2 ) + pow( dist1d[1], 2 ) );
260 
261  gap=false;
262  if (_currentLayout==ECALBARREL) {
263  if ( dist1d[2]<verySmallDist && // same z coord
264  distXY>(1.+slop)*cellsizeA && // bigger than one cell period, smaller than two
265  distXY<(2.-slop)*cellsizeA ) {
266  gap = true;
267  enFrac = (distXY-cellsizeA)/cellsizeA;
268  } else if (distXY<verySmallDist && // same x-y coord
269  dist1d[2]>(1.+slop)*cellsizeB &&
270  dist1d[2]<(2.-slop)*cellsizeB ) {
271  gap = true;
272  enFrac = (dist1d[2]-cellsizeB)/cellsizeB;
273  }
274 
275  } else { // endcap
276  if ( dist1d[1]<verySmallDist &&
277  dist1d[0]>(1.+slop)*cellsizeA &&
278  dist1d[0]<(2.-slop)*cellsizeA ) { // be careful, if different size in x,y may have to worry about stave
279  gap = true;
280  enFrac = (dist1d[0]-cellsizeA)/cellsizeA;
281  } else if ( dist1d[0]<verySmallDist &&
282  dist1d[1]>(1.+slop)*cellsizeB &&
283  dist1d[1]<(2.-slop)*cellsizeB ) { // be careful, if different size in x,y may have to worry about stave
284  gap = true;
285  enFrac = (dist1d[1]-cellsizeB)/cellsizeB;
286  }
287  }
288  if ( gap ) {
289 
290  streamlog_out ( DEBUG1 ) << " GOT A GAP " << endl;
291 
292  float position[3]={0.};
293  for (int k=0; k<3; k++)
294  position[k] = 0.5*(theseHits[ih]->getPosition()[k] + theseHits[jh]->getPosition()[k]);
295  float extraEnergy = enFrac*(theseHits[ih]->getEnergy() + theseHits[jh]->getEnergy())/2.;
296  float mintime = std::min( theseHits[ih]->getTime(), theseHits[jh]->getTime() );
297  CHT::CaloType cht_type = CHT::em;
298  CHT::CaloID cht_id = CHT::ecal;
299  CHT::Layout cht_lay = (_currentLayout == ECALBARREL) ? CHT::barrel : (_currentLayout == ECALENDCAP) ? CHT::endcap : CHT::any;
300  CalorimeterHitImpl* newGapHit = new CalorimeterHitImpl();
301  newGapHit->setEnergy( _intraModuleFactor* std::log ( 1 + _intraModuleNonlinearFactor*extraEnergy )/_intraModuleNonlinearFactor );
302  newGapHit->setPosition( position );
303  newGapHit->setTime( mintime );
304  newGapHit->setType( CHT( cht_type , cht_id , cht_lay , il) );
305  newcol->addElement( newGapHit );
306  } // if gap
307  } // jh
308  } // ih
309  } // >1 hit
310  } // im
311  } // is
312  } // ilayer
313 
314  streamlog_out ( DEBUG1 ) << " done addIntraModuleGapHits " << newcol->getNumberOfElements() << endl;
315 
316 
317 }
318 
320  // look for gaps between modules
321  // compare hits in same stave, same layer
322 
323  streamlog_out ( DEBUG1 ) << " starting addInterModuleGapHits" << endl;
324 
325 
326  const float verySmallDist = 0.01; // don't consider differences below this distance to be a gap
327  // const float expectedGap = 12.3; // expected gap between cell centres across module boundary (mm)
328 
329  for (int il=0; il<MAXLAYER; il++) {
330 
331  // we have to get the cell sizes here
332  float cellsizeA, cellsizeB;
333  if (_currentLayout==ECALBARREL) {
334  cellsizeA = _caloGeomData->layers[il].cellSize0; // phi dir in CM
335  cellsizeB = _caloGeomData->layers[il].cellSize1; // z dir
336  } else { // endcap - we should take care of the rotation with stave number if thse are different...
337  cellsizeA = _caloGeomData->layers[il].cellSize0; // x dir
338  cellsizeB = _caloGeomData->layers[il].cellSize1; // y dir
339  }
340  cellsizeA*=10; // to mm
341  cellsizeB*=10; // to mm
342 
343  for (int is=0; is<MAXSTAVE; is++) {
344 
345  for (int im=0; im<MAXMODULE; im++) {
346  std::vector < CalorimeterHit* > theseHits = hitsByLayerModuleStave[il][is][im];
347 
348  if ( theseHits.size()==0 ) continue;
349 
350  // look in next module
351  if ( im+1>=0 && im+1<MAXMODULE ) {
352  std::vector < CalorimeterHit* > nextHits = hitsByLayerModuleStave[il][is][im+1];
353  if ( nextHits.size()==0 ) continue;
354 
355  bool gap(false);
356  float enFrac(0);
357 
358  for ( size_t ih=0; ih<theseHits.size(); ih++) {
359 
360  for ( size_t jh=0; jh<nextHits.size(); jh++) {
361 
362  float dist1d[3];
363  for (int i=0; i<3; i++)
364  dist1d[i] = fabs( theseHits[ih]->getPosition()[i] - nextHits[jh]->getPosition()[i] );
365  float distXY = sqrt( pow( dist1d[0], 2 ) + pow( dist1d[1], 2 ) );
366  gap=false;
367 
368  if (_currentLayout==ECALBARREL) { // intermodule gaps only along z
369  if ( distXY<verySmallDist && // same phi coord
370  dist1d[2] < _interModuleDist + cellsizeB*1.9 ) { // _interModuleDist is expected distance between sensor edges
371  gap = true;
372  enFrac = dist1d[2] / cellsizeB;
373  }
374 
375  } else { // endcap
376  if ( dist1d[1]<verySmallDist && // same y
377  dist1d[0] < _interModuleDist + 1.9*cellsizeA ) { // be careful, if different size in x,y may have to worrk about stave
378  gap = true;
379  enFrac = dist1d[0]/cellsizeA;
380  } else if ( dist1d[0]<verySmallDist && // same x
381  dist1d[1] < _interModuleDist + 1.9*cellsizeB ) { // be careful, if different size in x,y may have to worrk about stave
382  gap = true;
383  enFrac = dist1d[1]/cellsizeB;
384  }
385  }
386  if ( gap ) {
387 
388  streamlog_out ( DEBUG1 ) << " addInterModuleGapHits: found gap " << dist1d[0] << " " << dist1d[1] << " " << dist1d[2]<< endl;
389 
390  float position[3]={0.};
391  for (int k=0; k<3; k++)
392  position[k] = 0.5*(theseHits[ih]->getPosition()[k] + nextHits[jh]->getPosition()[k]);
393  float extraEnergy = enFrac*(theseHits[ih]->getEnergy() + nextHits[jh]->getEnergy())/2.;
394  float mintime = std::min( theseHits[ih]->getTime(), nextHits[jh]->getTime() );
395  CHT::CaloType cht_type = CHT::em;
396  CHT::CaloID cht_id = CHT::ecal;
397  CHT::Layout cht_lay = (_currentLayout == ECALBARREL) ? CHT::barrel : (_currentLayout == ECALENDCAP) ? CHT::endcap : CHT::any;
398  CalorimeterHitImpl* newGapHit = new CalorimeterHitImpl();
399  newGapHit->setEnergy( _interModuleFactor* std::log ( 1 + _interModuleNonlinearFactor*extraEnergy )/_interModuleNonlinearFactor );
400  newGapHit->setPosition( position );
401  newGapHit->setTime( mintime );
402  newGapHit->setType( CHT( cht_type , cht_id , cht_lay , il) );
403  newcol->addElement( newGapHit );
404  } // if gap
405  } // jh
406  } // ih
407  } // >1 hit
408  } // im
409  } // is
410  } // ilayer
411 
412  streamlog_out ( DEBUG1 ) << " done addInterModuleGapHits " << newcol->getNumberOfElements() << endl;
413 
414  return;
415 }
416 
417 
419 }
void addInterModuleGapHits(LCCollectionVec *newcol)
void addIntraModuleGapHits(LCCollectionVec *newcol)
dd4hep::rec::LayeredCalorimeterData * _caloGeomData
static const float k
static const float e
void getGeometryData(const int ihitType)
std::vector< LCCollection * > LCCollectionVec
Definition: SiStripClus.h:55
BruteForceEcalGapFiller aBruteForceEcalGapFiller
std::vector< CalorimeterHit * > hitsByLayerModuleStave[MAXLAYER][MAXSTAVE][MAXMODULE]
const float slop
Definition: ILDCaloDigi.cc:36
virtual void processEvent(LCEvent *evt)