StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
StFtpcSlowSimReadout.cc
1 // $Id: StFtpcSlowSimReadout.cc,v 1.22 2018/12/07 18:00:17 genevb Exp $
2 // $Log: StFtpcSlowSimReadout.cc,v $
3 // Revision 1.22 2018/12/07 18:00:17 genevb
4 // Use TRandom and allow control of the seed
5 //
6 // Revision 1.21 2011/07/26 09:40:52 jcs
7 // Change LOG_DEBUG statement to print out 2 ftpcAmpSlope values to be able to
8 // check which ftpcAmpSlope table is being used
9 //
10 // Revision 1.20 2009/11/14 13:18:33 jcs
11 // change LOG_INFO messages to LOG_DEBUG messages
12 //
13 // Revision 1.19 2007/01/15 15:02:20 jcs
14 // replace printf, cout and gMesMgr with Logger
15 //
16 // Revision 1.18 2005/10/11 12:41:00 jcs
17 // If isec=6, set isec=0 to avoid segmentation violations
18 //
19 // Revision 1.17 2005/10/11 11:27:37 jcs
20 // remove +twopi in call to WhichPad when calculating pad_min,twopi is added in WhichPad
21 //
22 // Revision 1.16 2003/09/02 17:58:16 perev
23 // gcc 3.2 updates + WarnOff
24 //
25 // Revision 1.15 2003/01/29 12:12:37 fsimon
26 // Additional comments to illustrate ASIC mapping
27 //
28 // Revision 1.14 2003/01/14 12:58:25 jcs
29 // use Geometry_ftpc/ftpcAsicMap to control corrections for error in Y2001-2002
30 // FTPC asic mapping
31 //
32 // Revision 1.13 2002/10/17 13:42:11 fsimon
33 // Charge scaling taken out (assumes high amplification)
34 // use scaling to match 2001/2002 data
35 //
36 // Revision 1.12 2002/10/16 12:31:53 fsimon
37 // gain factors and time offset included, Hardware <-> DAQ mapping taken into
38 // account for Db access
39 //
40 // Revision 1.11 2002/09/13 13:44:02 fsimon
41 // Added Random noise to each Timebin -> Better description of real data
42 //
43 // Revision 1.10 2002/09/13 13:41:11 fsimon
44 // Comment out anglefactor
45 //
46 // Revision 1.9 2002/06/07 10:32:55 fsimon
47 // Correct treatment of clusters on sector boundaries
48 // Correct assignment of pad numbers in WhichPad
49 //
50 // Revision 1.8 2002/04/19 22:24:13 perev
51 // fixes for ROOT/3.02.07
52 //
53 // Revision 1.7 2001/04/24 07:17:12 oldi
54 // Renaming of some variables (slice->sslice, gnch->ggnch, glow->gglow,
55 // ghigh->gghigh, gdelta->ggdelta) to avoid compiler warnings (and bad coding
56 // style).
57 //
58 // Revision 1.6 2001/04/20 12:52:09 jcs
59 // change if/else statements for calculating polar coordinates to avoid
60 // problem with optimizer
61 // cleanup comments
62 //
63 // Revision 1.5 2001/04/02 12:04:37 jcs
64 // get FTPC calibrations,geometry from MySQL database and code parameters from StarDb/ftpc
65 //
66 // Revision 1.4 2001/03/19 15:53:10 jcs
67 // use ftpcDimensions from database
68 //
69 // Revision 1.3 2001/03/06 23:36:16 jcs
70 // use database instead of params
71 //
72 // Revision 1.2 2001/01/11 18:28:53 jcs
73 // use PhysicalConstants.h instead of math.h, remove print statement
74 //
75 // Revision 1.1 2000/11/23 10:16:43 hummler
76 // New FTPC slow simulator in pure maker form
77 //
78 //
80 // Author: W.G.Gong
81 // Email: gong@mppmu.mpg.de
82 // Date: Oct 25, 1996
83 //
84 // Modifications:
85 // 02/27/98 Janet Seyboth remove loop variable definitions, now
86 // in readout.h
87 // 02/18/98 Janet Seyboth Remove all references to point file
89 
90 #include <stdlib.h>
91 #include <Stiostream.h>
92 #include "PhysicalConstants.h"
93 
94 #include "StMessMgr.h"
95 #include "StFtpcSlowSimField.hh"
96 #include "StFtpcSlowSimCluster.hh"
97 #include "StFtpcSlowSimReadout.hh"
98 #include "StFtpcClusterMaker/StFtpcParamReader.hh"
99 #include "StFtpcClusterMaker/StFtpcDbReader.hh"
100 #include "TF1.h"
101 #include "TRandom.h"
102 
103 
104 #ifndef DEBUG
105 #define DEBUG 0
106 #endif
107 
108 StFtpcSlowSimReadout::StFtpcSlowSimReadout(StFtpcParamReader *paramReader,
109  StFtpcDbReader *dbReader,
110  float *adcIn,
111  const StFtpcSlowSimField *field)
112 {
113  if (!(gRandom->GetSeed())) gRandom->SetSeed(20181207);
114  LOG_INFO << "FtpcSlowSim Seed used = " << gRandom->GetSeed() << endm;
115  mParam=paramReader;
116  mDb=dbReader;
117  mRandomNumberGenerator = mParam->randomNumberGenerator();
118  number_plane = mDb->numberOfPadrowsPerSide();
119  pad_pitch = mDb->padPitch();
120  pad_length = mDb->padLength();
121  sigma_prf = mParam->sigmaPadResponseFuntion();
122  shaper_time = mParam->readoutShaperTime();
123  slice = mDb->microsecondsPerTimebin();
124 
125  mOuterRadius = mDb->sensitiveVolumeOuterRadius();
126 
127  mADCArray=adcIn;
128 
129  // set parameters for Polya distribution and initialize it
130  gnch = 50;
131  glow = 0.1;
132  ghigh = 2.5;
133  gdelta = (ghigh-glow) / (float) gnch;
134  pcum = new float[gnch];
135  polya(gnch, glow, ghigh, gdelta);
136 
137  int imax=mDb->numberOfPadrows()
138  *mDb->numberOfSectors()
139  *mDb->numberOfPads()
140  *mDb->numberOfTimebins();
141  for(int i=0; i<imax; ++i)
142  mADCArray[i] = 0.0;
143 
144  if (mRandomNumberGenerator == 1) {
145  // initialize the random number generator
146  rmarin(1802, 9373);
147  }
148 
149  // angle range in which each sector is calculated
150  phiMin = mDb->phiOrigin() * degree;
151  phiMax = mDb->phiEnd() * degree;
152  mGasGain = mDb->gasGain();
153  mMaxAdc = mParam->maxAdc();
154  mGaussIntSteps = mParam->gaussIntegrationSteps();
155  mInverseFinalVelocity = 1 / field->GetVelAtReadout();
156 }
157 
158 StFtpcSlowSimReadout::~StFtpcSlowSimReadout()
159 {
160  delete [] pcum;
161 }
162 
163 void StFtpcSlowSimReadout::Avalanche(const StFtpcSlowSimCluster *cl)
164 {
165  // sample the gas gain according to Polya distribution
166 
167  int group = 10; // group 10 electrons together
168  int nel = (int) ( cl->GetElectron() / group );
169  mFinalElectrons = 0;
170  for (int i=0; i<nel; ++i) {
171  mFinalElectrons += sample_polya(mGasGain);
172  }
173  mFinalElectrons *= group;
174 
175  // consider electron deflection due to Lorentz force
176  // when electron approaches the strip
177  // not implemented yet.
178 }
179 
180 void StFtpcSlowSimReadout::PadResponse(const StFtpcSlowSimCluster *cl)
181 {
182  float prf = sigma_prf;
183  float sig_phi = cl->GetSigPhi();
184  pad_off = cl->GetPadOff();
185 
186  if(DEBUG) {
187  LOG_DEBUG << "StFtpcSlowSimReadout::PadResponse: pad_off=" << pad_off << "sig_phi=" << sig_phi << endm;
188  }
189  sigma_pad = ::sqrt(sig_phi*sig_phi + prf*prf );
190 }
191 
192 
193 void StFtpcSlowSimReadout::ShaperResponse(const StFtpcSlowSimCluster *cl)
194 {
195  float srf = shaper_time*0.42466091; // time->sigma 1 / 2.35482
196  float sig_rad = cl->GetSigRad();
197  float rad_off = cl->GetRadOff();
198 
199  // convert the radial width to nsec
200  float sig_time = sig_rad * mInverseFinalVelocity;
201  time_off = 10000*rad_off * mInverseFinalVelocity;
202 
203  if(DEBUG) {
204  LOG_DEBUG << "ShaperResponse: time_off=" << time_off << "sig_rad=" << sig_rad << endm;
205  }
206  sigma_tim = ::sqrt( sig_time*sig_time + srf*srf) ;
207 }
208 
209 void StFtpcSlowSimReadout::Digitize(const StFtpcSlowSimCluster *cl, const int irow)
210 {
211  float n_sigmas_to_calc = 5.0;
212  // LOG_DEBUG <<"StFtpcSlowSimReadout::Digitize..." << endm;
213  // get the readout position in radial direction
214  float time_slice = mDb->microsecondsPerTimebin()*1000;// into nsec
215  float time = cl->GetDriftTime()*1000.; // into nsec
216  int itim = WhichSlice(time);
217 
218  // get the readout position in azimuthal direction
219  float delta_phi = mDb->radiansPerPad();
220  float phi = cl->GetPhi();
221  int isec, jsec, nsecs;
222  int ipad = WhichPad(phi,isec);
223 
224  if (DEBUG) {
225  LOG_DEBUG << "Digitize using parameters: mDb->radiansPerBoundary() = "<<mDb->radiansPerBoundary()<<" mDb->radiansPerPad() = "<<mDb->radiansPerPad()<<endm;
226  LOG_DEBUG << " phiMin = "<< phiMin << " phiMax = " << phiMax <<endm;
227  }
228 
229 
230 
231  // big if() loop
232  if ( itim > 2 && itim < (mDb->numberOfTimebins()-3))
233  {
234  // and calculate the pad distribution
235 
236  float sigmaPadCentimeters = sigma_pad *0.0001; // into cm
237  float width_phi = n_sigmas_to_calc *sigmaPadCentimeters / mOuterRadius;
238  //note: mOuterRadius is the radius of the Frisch grid, not the padplane,
239  // but for this purpose it is good enough
240 
241  // store center of cluster
242  float mid_phi = phi;
243  float mid_time = time;
244  float hypo = ::sqrt((pad_off/pad_pitch)*(pad_off/pad_pitch)
245  +(time_off/((double)mDb->microsecondsPerTimebin()*1000))*
246  (time_off/((double)mDb->microsecondsPerTimebin()*1000)));
247  int n_sub_hits = (int) (2*hypo);
248  int current_sub_hit;
249 
250  if(DEBUG) {
251  LOG_DEBUG << "hypo=" << hypo << " mid_phi=" << mid_phi << " mid_time=" << mid_time << " phi_off=" << pad_off/mOuterRadius << " time_off=" << time_off << endm;
252  }
253 
254  for(current_sub_hit=-n_sub_hits; current_sub_hit <= n_sub_hits; current_sub_hit++)
255  {
256  if(n_sub_hits>0)
257  {
258  time = mid_time + ((time_off/(2*n_sub_hits))*current_sub_hit);
259  phi = mid_phi + ((pad_off/(mOuterRadius*(2*n_sub_hits)))*current_sub_hit);
260  //note: mOuterRadius is the radius of the Frisch grid, not the padplane,
261  // but for this purpose it is good enough
262  }
263 
264  ipad = WhichPad(phi,isec);
265  if(DEBUG) {
266  LOG_DEBUG << current_sub_hit << "th subhit at time " << time << " phi " << phi << " => padpos " << mOuterRadius*phi <<" ipad = "<<ipad <<endm;
267  }
268  int isec_min;
269  int isec_max;
270  int pad_max_save=0;
271  int npad;
272  int pad_min = WhichPad(phi-width_phi,isec_min);
273  int pad_max = WhichPad(phi+width_phi,isec_max);
274 
275  if ( isec_min > isec_max )
276  nsecs = mDb->numberOfSectors() - isec_min + isec_max + 1;
277  else
278  if (isec_min == isec_max && pad_min >= pad_max )
279  nsecs = mDb->numberOfSectors() + 1;
280  else
281  nsecs = isec_max - isec_min + 1;
282  int isec = isec_min;
283  for (jsec=1; jsec<nsecs+1; ++jsec) {
284  if (isec != isec_max || (isec == isec_max && pad_min >= pad_max )) {
285  pad_max_save = pad_max;
286  pad_max = mDb->numberOfPads()-1;
287  }
288  npad = (pad_max - pad_min + 1);
289  float* pad = new float[npad]; // signal dist. in pads
290  int i;
291 
292  float dphi = fmod(phi-phiMin+twopi,twopi);
293  dphi = dphi - isec*(phiMax-phiMin);
294 
295  for (i=0; i<npad; ++i ) {
296  float phi_low = PhiOfPad(i+pad_min,0) - 0.5*delta_phi;
297  // low edge of pad
298  float phi_up = PhiOfPad(i+pad_min,0) + 0.5*delta_phi;
299  // up edge of pad
300  pad[i] = InteGauss(mOuterRadius*phi_low, mOuterRadius*phi_up,
301  mOuterRadius*dphi, sigmaPadCentimeters );
302  // integrate over this pad
303  //note: mOuterRadius is the radius of the Frisch grid, not the padplane,
304  // but for this purpose it is good enough:
305  // here padwidth=padpitch is assumed, too
306  } // end for loop
307 
308 
309  // and calculate the time distribution
310  // include time offset database: subtract time offset!
311  // move time center of cluster
312  if (DEBUG) {
313  LOG_DEBUG <<" Shifting time by " << endm;
314  LOG_DEBUG << mDb->timeOffset(GetHardSec(isec, irow)*mDb->numberOfPads()+GetHardPad(isec,ipad,irow)+1, irow) << " from "<< time << " with parameters "
315  << GetHardSec(isec, irow)*mDb->numberOfPads()+GetHardPad(isec,ipad,irow)+1<< " , "<< irow << endm;
316  }
317 
318  time = time - mDb->timeOffset(GetHardSec(isec, irow)*mDb->numberOfPads()+GetHardPad(isec,ipad,irow)+1, irow)/(0.001/mDb->microsecondsPerTimebin());
319 
320  if (DEBUG) {
321  LOG_DEBUG << " to " << time << " for Sec "<< isec<<" ("<<GetHardSec(isec, irow)<<") pad "<< (ipad) <<" ("<<GetHardPad(isec,ipad,irow)<<") row " << irow <<endm;
322  }
323 
324  float width_tim = n_sigmas_to_calc*sigma_tim;
325  int tim_min = WhichSlice(time - width_tim);
326  int tim_max = WhichSlice(time + width_tim);
327  int ntim = (tim_max - tim_min + 1);
328 
329  float* sca = new float[ntim];
330  int j;
331  for (j=0; j<ntim; ++j) {
332  float tim_low = TimeOfSlice(j+tim_min)
333  - 0.5*time_slice;
334  // low edge of time
335  float tim_up = TimeOfSlice(j+tim_min)
336  + 0.5*time_slice;
337  // up edge of time
338 
339  sca[j] = InteGauss(tim_low, tim_up, time, sigma_tim);
340  // integrate over this slice
341  } // end for loop
342 
343  // Now fill the mADCArray[irow,isec,pad,tim] array
344  if(DEBUG) {
345  LOG_DEBUG << current_sub_hit << "th subhit from time " << tim_min << " to " << tim_min+ntim << " pad " << pad_min << " to " << pad_min+npad << endm;
346  }
347  for (i=0; i<npad; ++i)
348  for (j=0; j<ntim; ++j) {
349  int k = irow*mDb->numberOfSectors()*mDb->numberOfPads()*mDb->numberOfTimebins()+isec*mDb->numberOfPads()*mDb->numberOfTimebins()+(i+pad_min)*mDb->numberOfTimebins() + (j+tim_min) ;
350  mADCArray[k] += (float)(mFinalElectrons * pad[i] * sca[j])/(2*n_sub_hits+1);
351  if(DEBUG) {
352  LOG_DEBUG << "Writing " << mADCArray[k] <<" to pad "<< (i+pad_min)<<endm;
353  }
354 
355  }
356 
357  // recycle sca[] and pad[]
358  delete [] sca;
359  delete [] pad;
360  pad_min = 0;
361  pad_max = pad_max_save;
362  ++isec;
363  if ( isec > mDb->numberOfSectors()-1 )
364  isec = 0;
365  } // end of loop over sectors for multisector cluster
366  } // end of loop over subhits
367  } // end big if() loop
368 
369 }
370 
371 
372 void StFtpcSlowSimReadout::OutputADC()
373 {
374  int num_pixels[11]={0}, num_pixels_occupied[11]={0};
375 
376  // Gaussian distribution for Noise, Sigma 1.5 ADC channels
377  TF1* noise = new TF1("noise","gaus",-5,5);
378  noise->SetParameters(1,0,1.5);
379  LOG_DEBUG << "FTPC SlowSimulator using random noise with a sigma of 1.5" << endm;
380  LOG_DEBUG << "FTPC SlowSimulator using gain tables (mDb->amplitudeSlope(0,1) = "<<mDb->amplitudeSlope(0,1)<<", mDb->amplitudeSlope(1,1) = "<<mDb->amplitudeSlope(1,1)<<"), amplitude offset and adcConversion = " << mParam->adcConversion()<< endm;
381 
382 
383  for (int row=0; row<mDb->numberOfPadrows(); row++) {
384  for (int sec=0; sec<mDb->numberOfSectors(); sec++) {
385  for (int pad=0; pad<mDb->numberOfPads(); pad++) {
386  for (int bin=0; bin<mDb->numberOfTimebins(); bin++) {
387  int i=bin+mDb->numberOfTimebins()*pad+mDb->numberOfTimebins()*mDb->numberOfPads()*sec+mDb->numberOfTimebins()*mDb->numberOfPads()*mDb->numberOfSectors()*row;
388 
389  if (mADCArray[i] != 0){
390  mADCArray[i] =(mADCArray[i] / mParam->adcConversion());
391  //mADCArray[i] =(mADCArray[i] / 1.4); // Scale ADC Values to match real data
392 
393  // include gainfactors
394  // remember that the Db access counts from 1 to 960 and not from 0 to 959 for the sector&pad index!
395  mADCArray[i] = mADCArray[i] - mDb->amplitudeOffset(GetHardSec(sec, row)*mDb->numberOfPads()+GetHardPad(sec,pad,row)+1, row);
396  if (DEBUG) {
397  LOG_DEBUG << "Using AmpSlope :" << mDb->amplitudeSlope(GetHardSec(sec, row)*mDb->numberOfPads()+GetHardPad(sec,pad,row)+1, row) <<endm;
398  }
399  if (mDb->amplitudeSlope(GetHardSec(sec, row)*mDb->numberOfPads()+GetHardPad(sec,pad,row)+1, row)!= 0)
400  mADCArray[i] = mADCArray[i] / (mDb->amplitudeSlope(GetHardSec(sec, row)*mDb->numberOfPads()+GetHardPad(sec,pad,row)+1, row));
401  else
402  mADCArray[i] = 0;
403 
404 
405  if(DEBUG)
406  num_pixels[(int) (bin/30)]++;
407 
408  // Add random noise to each timebin
409  mADCArray[i] += noise->GetRandom();
410 
411  if(mADCArray[i] >= mParam->zeroSuppressThreshold()) {
412 
413  // count up occupancy
414  if(DEBUG)
415  num_pixels_occupied[(int) (bin/30)]++;
416 
417  if (mADCArray[i] >= mMaxAdc)
418  mADCArray[i] = mMaxAdc; // reset overflow
419  }
420  }
421  }
422  }
423  }
424  }
425  if (DEBUG) {
426  LOG_DEBUG << "Occupancies:" << endm;
427  for(int lastloop=0; lastloop<11;lastloop++)
428  {
429  if(num_pixels[lastloop]>0) {
430  LOG_DEBUG << "bin " << lastloop << " has occupancy" << num_pixels_occupied[lastloop]/(float) num_pixels[lastloop] << endm;
431  }
432  }
433  }
434 
435  delete noise;
436  return;
437 }
438 
439 float StFtpcSlowSimReadout::PhiOfPad(const int pad, const int deg_or_rad)
440 {
441  return (pad+0.5)*mDb->radiansPerPad() + mDb->radiansPerBoundary()/2;
442 }
443 
444 int StFtpcSlowSimReadout::WhichPad(const float phi, int &isec)
445 {
446  // phi and phi_min in rad
447  float dphi = fmod(phi-phiMin+twopi,twopi);
448  isec = (int)(dphi/(phiMax-phiMin));
449  // Due to insufficient numerical precision, it is possible that in some cases isec=6
450  // but 0<=isec<=5. If isec=6, set isec=0 to avoid segmentation violations
451  if (isec == 6) isec = 0;
452  dphi = dphi - isec*(phiMax-phiMin)- mDb->radiansPerBoundary()/2;
453  int ipad = (int) (dphi/mDb->radiansPerPad()); // no +0.5 since pad 0 really starts at 0 and ends at 1
454  if (ipad < 0) {
455  ipad = 0;
456  }
457  if (ipad > mDb->numberOfPads() - 1) {
458  ipad = mDb->numberOfPads() - 1;
459  }
460 
461  return ipad;
462 }
463 
464 int StFtpcSlowSimReadout::WhichSlice(const float time)
465 {
466  int itim = (int) (time*0.001/mDb->microsecondsPerTimebin()) ; // time in nsec
467  if (itim < 0) {
468  itim = 0;
469  }
470  if (itim > mDb->numberOfTimebins() - 1) {
471  itim = mDb->numberOfTimebins() - 1;
472  }
473  return itim;
474 }
475 
476 float StFtpcSlowSimReadout::TimeOfSlice(const int sslice)
477 {
478  return (sslice+0.5)*1000*mDb->microsecondsPerTimebin(); // time in nsec
479 }
480 
481 int StFtpcSlowSimReadout::GetHardPad(const int daqsec, const int daqpad, const int irow)
482 {
483  // ATTENTION: This function is only used for correct db access (gain table, time offset...)
484  // The asic mapping for the output is done in StFtpcRawWriter
485 
486  int pad = daqpad;
487  if (pad <0) pad =0;
488  if (pad > (mDb->numberOfPads() -1)) pad = mDb->numberOfPads() -1;
489  if (irow>=10)
490  if (mDb->Asic2EastNotInverted() && (pad>63)&&(pad<96)) // no turning for center FEE card in each sector in East
491  return pad; // for old data (prior to 2003)
492  else
493  return (mDb->numberOfPads()-pad-1);
494  else
495  return (mDb->numberOfPads()-pad-1);
496 
497 }
498 
499 
500 int StFtpcSlowSimReadout::GetHardSec(const int daqsec, const int irow)
501 {
502  int sec = daqsec;
503  if (sec < 0) sec = 0;
504  if (sec > (mDb->numberOfSectors() -1 )) sec = mDb->numberOfSectors() -1;
505 
506  if (irow>=10)
507  return sec;
508  else
509  return (mDb->numberOfSectors()-sec-1);
510 }
511 
512 void StFtpcSlowSimReadout::Print() const
513 {
514 
515  LOG_INFO << "StFtpcSlowSimReadout::Print ";
516  LOG_INFO << " Number of pad rows = "
517  << mDb->numberOfPadrows() << endm;
518  LOG_INFO << " Number of pad per row = "
519  << mDb->numberOfPads() << endm;
520  LOG_INFO << " Pad length = "
521  << pad_length
522  << " pitch = "
523  << pad_pitch << " [cm]" << endm;
524  LOG_INFO << " Shaping time = "
525  << shaper_time << " [ns]" << endm;
526  LOG_INFO << " Time slice = "
527  << mDb->microsecondsPerTimebin()*1000 << " [ns]" << endm;
528  LOG_INFO << " Pad response sigma = "
529  << sigma_prf << " [um]" << endm;
530 
531 }
532 
533 
534 void StFtpcSlowSimReadout::polya(const int ggnch, const float gglow,
535  const float gghigh, const float ggdelta)
536 {
537 // generate probability distribution from
538 // Polya function for gain fluctuation
539 // c.f.: Ronaldo Bellazzini and Mario Spezziga
540 // La Rivista del Nuovo Cimento V17N12(1994)1.
541 //
542 // m=3/2, gamma(m)=::sqrt(pi)/2=0.8862269
543 // polya(k) = m*::pow((m*k),(m-1))*exp(-m*k)/gamma(m)
544 //
545  float m_polya = 1.5;
546  float c_polya = 1.6925687;
547 
548  float x;
549  float p;
550  pcum[0] = 0.0;
551  int i;
552  for (i=1; i<ggnch; ++i) {
553  x = m_polya*(i*ggdelta+gglow);
554  p = c_polya*::pow(double(x),double(m_polya-1.0))*exp(-x);
555  pcum[i] = pcum[i-1] + p ;
556  }
557 
558  for (i=0; i<ggnch; ++i) {
559  pcum[i] /= pcum[ggnch-1]; // renormalize it
560  //LOG_DEBUG << "i=" << i << " pcum=" << pcum[i] << endm;
561  }
562 }
563 
564 int StFtpcSlowSimReadout::sample_polya(const float gain)
565 {
566  float ran;
567 
568  if (mRandomNumberGenerator == 0)
569  {
570  ran = gRandom->Rndm();
571  }
572  else
573  {
574  ran = ranmar();
575  }
576 
577  int ich = Locate(gnch, pcum, ran);
578  //LOG_DEBUG << "ich = " << ich << endm;
579  return (int) ( gain * ( glow + ich * gdelta ) );
580 
581 }
582 
583 float StFtpcSlowSimReadout::InteGauss(const float x_1, const float x_2,
584  const float x_0, const float sig)
585 {
586 
587  float x,x1,x2 ;
588 
589  x1 = (x_1-x_0) /sig;
590  x2 = (x_2-x_0) /sig;
591  if (x1 > x2) {
592  x = x2; x2 = x1; x1 = x;
593  }
594 
595  float del_x = (x2-x1)/((float) (mGaussIntSteps-1) );
596 
597  // integrate the gauss function
598  float sum = 0;
599  x = x1 + 0.5*del_x ;
600  for( int i=0; i<(mGaussIntSteps-1); ++i ) {
601  sum += exp(-0.5*x*x);
602  x += del_x;
603  }
604 
605  return del_x*0.39894228*sum; // 1/::sqrt(twopi)=0.39894228
606 }
607 
608 float StFtpcSlowSimReadout::ranmar()
609 {
610  /* Universal random number generator proposed by Marsaglia */
611  /* and Zaman in report FSU-SCRI-87-50 */
612 
613  /* From "A Review of Pseudorandom Number Generators" by */
614  /* F. James, CERN report SOFTWR 88-20. */
615 
616  /* Rewritten as a function by Bill Long, 26-may-1989. */
617  /* Also modified to move cd and cm from initialization */
618  /* routine RMARIN to here as parameters. */
619 
620  float uni;
621  float cd;
622  float cm;
623  int i = 97, j = 33;
624 
625  cd = (float) 7654321./(float)16777216.;
626  cm = (float)16777213./(float)16777216.;
627 
628  // LOG_DEBUG << Form("cd = %20.17f; cm = %20.17f", cd, cm) << endm;
629 
630  uni = uc.u[i-1] - uc.u[j-1];
631  if (uni < (float)0.0) uni += (float)1.0;
632 
633  uc.u[i-1] = uni;
634 
635  --i;
636  if (i == 0) i = 97;
637 
638  --j;
639  if (j == 0 ) j = 97;
640 
641  uc.c -= cd;
642  if (uc.c < (float)0.0) uc.c += cm;
643 
644  uni -= uc.c;
645  if (uni < (float)0.0) uni += (float) 1.0;
646 
647  return 0.5;
648 }
649 
650 void StFtpcSlowSimReadout::rmarin(int ij, int kl)
651 {
652  /* Initializing routine for RANMAR, must be called before */
653  /* generating any psuedorandom numbers with RANMAR. The */
654  /* input values should be in the ranges: */
655  /* 0 <= ij <= 31328 */
656  /* 0 <= kl <= 30081 */
657 
658  /* This shows correspondence between the simplified seeds */
659  /* ij,kl and the original Marsaglia-Zaman seeds i,j,k,l */
660  /* To get standard values in Marsaglia-Zaman paper */
661  /* (i=12, j=34, k=56, l=78) put ij=1802, kl=9373. */
662 
663  int ii, jj;
664  int i, j, k, l, m;
665  float s, t;
666 
667  i = (ij/177) % 177 + 2;
668  j = (ij) % 177 + 2;
669  k = (kl/169) % 178 + 1;
670  l = (kl) % 169;
671 
672  LOG_DEBUG << "Ranmar initialized:" << ij << " "
673  << kl << " "
674  << i << " "
675  << j << " "
676  << k << " "
677  << l << endm;
678 
679  for(ii=0; ii<97; ii++) {
680 
681  s = 0.0;
682  t = 0.5;
683 
684  for(jj=0; jj<24; jj++) {
685 
686  m = ( (i*j) % 179 )*k % 179;
687  i = j;
688  j = k;
689  k = m;
690  l = (53*l+1) % 169;
691 
692  if ( (l*m)%64 >= 32 ) s += t;
693  t *= 0.5;
694 
695  }
696 
697  uc.u[ii] = s;
698  // LOG_DEBUG << "ii = " << ii << " s= " << s << endm;
699  }
700 
701  uc.c = 362436./16777216.;
702 
703  // LOG_DEBUG << "c= " << uc.c << endm;
704 
705 }
706 
707 
708 
709 
710 
711 
712 
713 
714 
715 
716 
717 
718 
719 
720 
721 
722 
723 
724