StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
StFmsFastSimulatorMaker.cxx
Go to the documentation of this file.
1 // $Id: StFmsFastSimulatorMaker.cxx,v 1.11 2018/01/03 15:25:19 akio Exp $
2 //
3 // $Log: StFmsFastSimulatorMaker.cxx,v $
4 // Revision 1.11 2018/01/03 15:25:19 akio
5 // update for FPost
6 //
7 // Revision 1.10 2017/09/28 17:07:19 akio
8 // addoing bitshiftgain
9 //
10 // Revision 1.9 2017/05/03 15:54:21 akio
11 // added gain scaling when attenuation was on during geant simulation
12 //
13 // Revision 1.8 2016/06/07 15:51:41 akio
14 // Making code better based on Coverity reports
15 //
16 // Revision 1.7 2015/10/29 21:19:16 akio
17 // adjust debug prints
18 //
19 // Revision 1.6 2015/10/20 19:52:36 akio
20 // Setting default for mFpsNPhotonPerMIP to 100.0
21 //
22 // Revision 1.5 2015/09/29 16:28:58 akio
23 // setFmsZS(int v) and if ADC<v, drop the hit (default=2)
24 // adding poisson distribution for FPS, with setFpsNPhotonPerMIP(float v)
25 // (default=0 for now, which turns this off. It should be around 100?)
26 //
27 // Revision 1.4 2015/09/18 18:44:28 akio
28 // uses StEnumeration
29 //
30 // Revision 1.3 2015/02/26 23:53:04 yuxip
31 // new update from Akio
32 //
33 // Revision 1.2 2014/05/06 16:05:56 jeromel
34 // Adjust for include - there is no need to specify the path
35 //
36 // Revision 1.1 2014/05/06 16:02:04 jeromel
37 // First version of StFmsFastSimulatorMaker deliverred upon review
38 //
46 
47 #include <algorithm> // For std::fill(), std::max(), std::min()
48 
49 #include "St_base/StMessMgr.h"
50 #include "StEvent/StEvent.h"
51 #include "StEvent/StFmsCollection.h"
52 #include "StEvent/StFmsHit.h"
53 #include "StFmsDbMaker/StFmsDbMaker.h"
54 #include "tables/St_g2t_emc_hit_Table.h"
55 #include "tables/St_fpdm_fmcg_Table.h"
56 
57 
58 #include "TRandom2.h"
59 
60 /* Constructor. */
62  StMaker(name),mFpsDEPerMIP(0.0016),mFpsNPhotonPerMIP(100.0) { }
63 
64 /* Process one event. */
66  LOG_DEBUG << "StFmsFastSimulatorMaker::Make" << endm;
67  // Check for the FMS database maker, bail out if it can't be located.
68  if (!GetMaker("fmsDb")) {
69  LOG_ERROR << "No StFmsDbMaker. StFmsDbMaker library not loaded?" << endm;
70  return kStErr;
71  } // if
72  // Get the existing StEvent, or add one if it doesn't exist.
73  StEvent* event = static_cast<StEvent*>(GetDataSet("StEvent"));
74  if (!event) {
75  event = new StEvent;
76  AddData(event);
77  LOG_DEBUG << "Creating StEvent" << endm;
78  } // if
79  // Add an FMS collection to the event if one does not already exist.
80  if (!event->fmsCollection()) {
81  event->setFmsCollection(new StFmsCollection);
82  LOG_DEBUG << "Creating StFmsCollection" << endm;
83  } // if
84 
85  // Check if attenuation was on/off
86  // Get the wrapper to the FMCG table (may need to play with the path...)
87  St_fpdm_fmcg* FMCG = (St_fpdm_fmcg*) GetChain()-> Find("bfc/.make/geant/.const/geom/fpdm_fmcg");
88  // Get the first (only) row of the structure
89  if(FMCG){
90  fpdm_fmcg_st* fmcg = (fpdm_fmcg_st*)FMCG->At(0);
91  if(fmcg){
92  // Get the attenuation flag
93  mAttenuation = fmcg->atten;
94  LOG_DEBUG << "Found St_fpdm_fmcg* at bfc/.make/geant/.const/geom/fpdm_fmcg and atten="<<mAttenuation<<endm;
95  }else{
96  LOG_INFO << "Fail to get fpdm_fmcg_st" << endm;
97  }
98  }else{
99  LOG_INFO << "Fail to find St_fpdm_fmcg* at bfc/.make/geant/.const/geom/fpdm_fmcg" << endm;
100  }
101 
102  // Digitize GEANT FPD/FMS hits
103  fillStEvent(event);
104  if(Debug()) printStEventSummary(event);
105  return kStOk;
106 }
107 
108 /* Fill an event with StFmsHits. */
109 void StFmsFastSimulatorMaker::fillStEvent(StEvent* event) {
110  // Existence of StFmsDbMaker was already checked in Make()
111  // so we don't confirm the pointer again here.
112  // Decode detector information from hit:
113  StFmsDbMaker* dbMaker = static_cast<StFmsDbMaker*>(GetMaker("fmsDb"));
114  StFmsCollection * fmscollection = event->fmsCollection();
115 
116  // Read the g2t table
117  St_g2t_emc_hit* hitTable = static_cast<St_g2t_emc_hit*>(GetDataSet("g2t_fpd_hit"));
118  if (!hitTable) {
119  LOG_DEBUG << "g2t_fpd_hit table is empty" << endm;
120  return; // Nothing to do
121  } // if
122 
123  // Loop over FPD hits and accumurate hits
124  const Int_t nHits = hitTable->GetNRows();
125  //LOG_DEBUG << "g2t_fpd_hit table has " << nHits << " hits" << endm;
126  if(nHits<1){
127  LOG_DEBUG << "g2t_fpd_hit table has 0 rows" << endm;
128  return;
129  }
130  const g2t_emc_hit_st* hit = hitTable->GetTable();
131  if(!hit){
132  LOG_DEBUG << "g2t_fpd_hit GetTable failed" << endm;
133  return;
134  }
135 
136  StPtrVecFmsHit hits; //temp storage for hits
137  //table to keep pointer to hit for each det & channel
138  static const int NDET=16, NCH=600;
139  //StFmsHit* map[NDET][NCH]; using heap memory (new) instead of stack (local)
140  //memset(map,0,sizeof(map));
141  auto map = new StFmsHit*[NDET][NCH](); //no need for memset with ()
142 
143  for (Int_t i=0; i < nHits; ++i) {
144  if (hit) {
145  const Int_t detectorId = getDetectorId(*hit);
146  Int_t channel;
147  if(detectorId==kFpsDetId) {
148  channel=dbMaker->fpsSlatIdFromG2t(hit->volume_id);
149  }else if(detectorId==kFpostDetId) {
150  channel=dbMaker->fpostSlatIdFromG2t(hit->volume_id);
151  }else{
152  channel=hit->volume_id % 1000;
153  }
154  LOG_INFO << Form("volid=%8d det=%2d ch=%4d e=%f\n",hit->volume_id,detectorId,channel,hit->de);
155  if(detectorId<0 || detectorId>=NDET || channel<0 || channel>=NCH){
156  LOG_DEBUG << Form("det or ch out of range det=%d ch=%d",detectorId,channel) << endm;
157  continue;
158  }
159  Float_t energy = hit->de;
160  StFmsHit* fmshit=0;
161  if(map[detectorId][channel]==0){ // New hit
162  Int_t qtCrate, qtSlot, qtChannel, adc=0, tdc=0;
163  if(detectorId==kFpsDetId){ //FPS
164  qtCrate=6;
165  dbMaker->fpsQTMap(channel,&qtSlot,&qtChannel);
166  }else if(detectorId==kFpostDetId){ //FPOST
167  qtCrate=7;
168  dbMaker->fpostQTMap(channel,&qtSlot,&qtChannel);
169  }else{ //FMS
170  dbMaker->getMap(detectorId, channel, &qtCrate, &qtSlot, &qtChannel);
171  }
172  fmshit = new StFmsHit(detectorId, channel, qtCrate, qtSlot, qtChannel, adc, tdc, energy);
173  hits.push_back(fmshit);
174  map[detectorId][channel]=fmshit;
175  }else{ // Adding energy to old hit
176  fmshit = map[detectorId][channel];
177  fmshit->setEnergy(fmshit->energy() + energy);
178  }
179  hit++;
180  }
181  }
182  int nfmshit=hits.size();
183  delete [] map;
184 
185  // Loop over hits and digitize
186  for(int i=0; i<nfmshit; i++){
187  const Int_t detectorId = hits[i]->detectorId();
188  const Int_t channel = hits[i]->channel();
189  Float_t energy=hits[i]->energy();
190  Float_t gain, gainCorrection;
191  int adc;
192  if(detectorId==kFpsDetId){ //FPS
193  gain = 1.0/dbMaker->fpsGain(channel); //fpsGain gives ADCch for MIP peak
194  gainCorrection=mFpsDEPerMIP; //about 1.6MeV per MIP
195  //add smering with poisson distriubtion
196  if(mFpsNPhotonPerMIP>0.0){
197  static TRandom2 rnd;
198  int nPixel=static_cast<Int_t>(energy/gainCorrection*mFpsNPhotonPerMIP);
199  int nPixelMod = rnd.Poisson(nPixel);
200  energy = nPixelMod*gainCorrection/mFpsNPhotonPerMIP;
201  }
202  }else if(detectorId==kFpostDetId){ //FPOST
203  gain = 1.0/dbMaker->fpostGain(channel); //fpostGain gives ADCch for MIP peak
204  gainCorrection=mFpsDEPerMIP; //about 1.6MeV per MIP
205  //add smering with poisson distriubtion
206  if(mFpsNPhotonPerMIP>0.0){
207  static TRandom2 rnd;
208  int nPixel=static_cast<Int_t>(energy/gainCorrection*mFpsNPhotonPerMIP);
209  int nPixelMod = rnd.Poisson(nPixel);
210  energy = nPixelMod*gainCorrection/mFpsNPhotonPerMIP;
211  }
212 
213  }else{
214  // Get gain and correction from the database.
215  gain = dbMaker->getGain(detectorId, channel);
216  gainCorrection = dbMaker->getGainCorrection(detectorId, channel);
217  }
218  // Digitize
219  if(mAttenuation==0){
220  adc = static_cast<Int_t>(energy / (gain * gainCorrection) + 0.5);
221  }else{
222  adc = static_cast<Int_t>(energy / mAttenuationGainScale / (gain * gainCorrection) + 0.5);
223  }
224  if(mFmsBitShiftGain){
225  short bitshift = dbMaker->getBitShiftGain(detectorId,channel);
226  if(bitshift>0){
227  adc = adc & (0x0fff << bitshift);
228  }else if(bitshift<0){
229  adc = std::min(adc, (0x1<<(12+bitshift))-1 );
230  }
231  }
232  // Check for ADC values outside the allowed range and cap.
233  adc = std::max(adc, 0); // Prevent negative ADC
234  adc = std::min(adc, 4095); // Cap maximum ADC = 4,095
235  // Recalculate energy accounting for ADC range
236  Float_t digi_energy;
237  if(detectorId!=kFpsDetId && detectorId!=kFpostDetId){
238  digi_energy = adc * gain * gainCorrection;
239  }else{
240  digi_energy = adc * gain; //for FPS, this is not really energy but # of MIPs
241  }
242  if(adc>mFmsZSch){ //store only if significant energy deposit : adc>mFmsZSch(default=2)
243  hits[i]->setAdc(adc);
244  hits[i]->setEnergy(digi_energy);
245  fmscollection->addHit(hits[i]);
246  // if(Debug())
247  cout << Form("Det=%2d Ch=%3d E=%8.3f gain=%6.3f ADC=%4d digiE=%8.3f\n",detectorId,channel,energy,gain,adc,digi_energy);
248  }else{
249  delete hits[i];
250  }
251  }
252  LOG_INFO << Form("Found %d g2t hits in %d cells, created %d hits with ADC>0",nHits,nfmshit,fmscollection->numberOfHits()) <<endm;
253 }
254 
255 /*
256  Returns the standard ID for the detector containing a hit.
257 
258  Detector parameters are defined as follows in the database:
259  Name ID type ew ns nx ny
260  FPD-north 0 0 0 0 7 7
261  FPD-south 1 0 0 1 7 7
262  FPD-north-preshower 2 1 0 0 7 1
263  FPD-south-preshower 3 1 0 1 7 1
264  FPD-north-smdv 4 2 0 0 48 1
265  FPD-south-smdv 5 2 0 1 48 1
266  FPD-north-smdh 6 3 0 0 1 48
267  FMS-south-smdh 7 3 0 1 1 48
268  FMS-north-large 8 4 1 0 17 34
269  FMS-south-large 9 4 1 1 17 34
270  FMS-north-small 10 0 1 0 12 24
271  FMS-south-small 11 0 1 1 12 24
272  where
273  - ew is the east-or-west location: 0 = east (the FPD), 1 = west (the FMS)
274  - ns is the north-or-south location: 0 = north, 1 = south
275  - nx, ny is the number of x, y channels
276  - type corresponds to:
277  - 0 = Small cell
278  - 1 = Preshower
279  - 2 = SMD-V
280  - 3 = SMD-H
281  - 4 = Large cell
282  - 5 = Hadron calorimetry
283  See:
284  http://online.star.bnl.gov/dbExplorer/# --> Geometry/fms/ChannelGeometry
285  Look into pams/sim/g2t/g2t_volume_id.g
286  and search for FLGR (small pbg) or FLXF (large pbg).
287  For FPS, there is no entry in fms/ChannelGeometry.
288  Just assign detector Id=15 here.
289 
290 Email from Akio describing decoding of the g2t volume ID, 16th Jan 2014:
291 
292  G2T volume id is currently
293  id = ew*10000+nstb*1000+ch
294  where
295  ew: 1=fpd, 2=fms
296  nstb for ew=1(FPD):
297  1=north, 2=south, 3=top, 4=bottom
298  5=north pbG preshower, 6=south pbg preshower
299  nstb for ew=2(FMS):
300  1=north large, 2=south large
301  3=north small, 4=south small ch: channel#
302 
303  For FPS where id>100000:
304  id = 100000+ew*10000+quad*1000+layr*100+slat
305  where
306  ew = always 1 for west
307  quad = 1 to 4
308  layr = 1 to 3
309  slat = 1 to 21
310  Fms/fpd volume id does NOT change at all.
311 */
312 
313 Int_t StFmsFastSimulatorMaker::getDetectorId(const g2t_emc_hit_st& hit) const {
314  enum { kFpd = 1, kFms = 2, kNorth = 0, kSouth = 1 };
315  const Int_t volumeId = hit.volume_id;
316  printf("voldid=%d\n",volumeId);
317  // Decode volume ID into detector type, fpd/fms and north/south locations
318  const Int_t isFPS = volumeId / 100000;
319  const Int_t fpdOrFms = (volumeId % 100000) / 10000;
320  const Int_t module = (volumeId % 10000) / 1000;
321  if(isFPS==1) return kFpsDetId;
322  if(isFPS==2) return kFpostDetId;
323  switch (fpdOrFms) {
324  case kFpd:
325  switch (module) {
326  case 1: return kFpdNorthDetId; // north
327  case 2: return kFpdSouthDetId; // south
328  case 5: return kFpdNorthPrsDetId; // preshower north
329  case 6: return kFpdSouthPrsDetId; // preshower south
330  } // switch
331  break;
332  case kFms:
333  switch (module) {
334  case 1: return kFmsNorthLargeDetId; // north large cells
335  case 2: return kFmsSouthLargeDetId; // south large cells
336  case 3: return kFmsNorthSmallDetId; // north small cells
337  case 4: return kFmsSouthSmallDetId; // south small cells
338  } // switch
339  break;
340  } // switch
341  return -1;
342 }
343 
344 /* Dump hit information to LOG_INFO. */
345 void StFmsFastSimulatorMaker::printStEventSummary(const StEvent* event) {
346  const Int_t NDETECTORS = 16;
347  const Char_t* detectorNames[NDETECTORS] = {
348  "FPD-North ",
349  "FPD-South",
350  "FPD-North-Pres",
351  "FPD-South-Pres",
352  "FPD-North-SMDV",
353  "FPD-South-SMDV",
354  "FPD-North-SMDH",
355  "FPD-South-SMDH",
356  "FMS-North-Large",
357  "FMS-South-Large",
358  "FMS-North-Small",
359  "FMS-South-Small",
360  "FHC-North",
361  "FHC-South",
362  "FMS-PreShower",
363  "FMS-PostShower"
364  };
365  // Array of total hits per subdetector, initialised to all zeros
366  Int_t nhits[NDETECTORS];
367  std::fill(nhits, nhits + NDETECTORS, 0);
368  // Array of total energy per sub-detector, initialised to all zeros
369  Float_t detectorEnergy[NDETECTORS];
370  std::fill(detectorEnergy, detectorEnergy + NDETECTORS, 0.f);
371  // Sum number of hits and energies
372  const StSPtrVecFmsHit& hits = event->fmsCollection()->hits();
373  for (size_t i = 0; i < hits.size(); ++i) {
374  const StFmsHit* hit = hits[i];
375  ++nhits[hit->detectorId()];
376  detectorEnergy[hit->detectorId()] += hit->energy();
377  if(Debug()>1) hit->print();
378  } // for
379  // Print detectors summary
380  LOG_INFO << "ID\tNAME\t\tNHITS\tENERGY" << endm;
381  for (Int_t detectorId = 0; detectorId < NDETECTORS; ++detectorId) {
382  if(nhits[detectorId]>0)
383  LOG_INFO << detectorId << '\t' << detectorNames[detectorId] << '\t'
384  << nhits[detectorId] << '\t' << detectorEnergy[detectorId] << endm;
385  } // for
386 }
Float_t getGainCorrection(Int_t detectorId, Int_t ch) const
get the gain for the channel
virtual void AddData(TDataSet *data, const char *dir=".data")
User methods.
Definition: StMaker.cxx:332
StFmsFastSimulatorMaker(const Char_t *name="fmsSim")
Short_t getBitShiftGain(Int_t detectorId, Int_t ch) const
get the gain correction for the channel
Definition: Stypes.h:44
Definition: Stypes.h:41
virtual TDataSet * Find(const char *path) const
Definition: TDataSet.cxx:362