92 #include "PhysicalConstants.h"
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"
113 if (!(gRandom->GetSeed())) gRandom->SetSeed(20181207);
114 LOG_INFO <<
"FtpcSlowSim Seed used = " << gRandom->GetSeed() << endm;
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();
125 mOuterRadius = mDb->sensitiveVolumeOuterRadius();
133 gdelta = (ghigh-glow) / (
float) gnch;
134 pcum =
new float[gnch];
135 polya(gnch, glow, ghigh, gdelta);
137 int imax=mDb->numberOfPadrows()
138 *mDb->numberOfSectors()
140 *mDb->numberOfTimebins();
141 for(
int i=0; i<imax; ++i)
144 if (mRandomNumberGenerator == 1) {
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();
158 StFtpcSlowSimReadout::~StFtpcSlowSimReadout()
168 int nel = (int) ( cl->GetElectron() / group );
170 for (
int i=0; i<nel; ++i) {
171 mFinalElectrons += sample_polya(mGasGain);
173 mFinalElectrons *= group;
182 float prf = sigma_prf;
183 float sig_phi = cl->GetSigPhi();
184 pad_off = cl->GetPadOff();
187 LOG_DEBUG <<
"StFtpcSlowSimReadout::PadResponse: pad_off=" << pad_off <<
"sig_phi=" << sig_phi << endm;
189 sigma_pad = ::sqrt(sig_phi*sig_phi + prf*prf );
195 float srf = shaper_time*0.42466091;
196 float sig_rad = cl->GetSigRad();
197 float rad_off = cl->GetRadOff();
200 float sig_time = sig_rad * mInverseFinalVelocity;
201 time_off = 10000*rad_off * mInverseFinalVelocity;
204 LOG_DEBUG <<
"ShaperResponse: time_off=" << time_off <<
"sig_rad=" << sig_rad << endm;
206 sigma_tim = ::sqrt( sig_time*sig_time + srf*srf) ;
211 float n_sigmas_to_calc = 5.0;
214 float time_slice = mDb->microsecondsPerTimebin()*1000;
215 float time = cl->GetDriftTime()*1000.;
216 int itim = WhichSlice(time);
219 float delta_phi = mDb->radiansPerPad();
220 float phi = cl->GetPhi();
221 int isec, jsec, nsecs;
222 int ipad = WhichPad(phi,isec);
225 LOG_DEBUG <<
"Digitize using parameters: mDb->radiansPerBoundary() = "<<mDb->radiansPerBoundary()<<
" mDb->radiansPerPad() = "<<mDb->radiansPerPad()<<endm;
226 LOG_DEBUG <<
" phiMin = "<< phiMin <<
" phiMax = " << phiMax <<endm;
232 if ( itim > 2 && itim < (mDb->numberOfTimebins()-3))
236 float sigmaPadCentimeters = sigma_pad *0.0001;
237 float width_phi = n_sigmas_to_calc *sigmaPadCentimeters / mOuterRadius;
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);
251 LOG_DEBUG <<
"hypo=" << hypo <<
" mid_phi=" << mid_phi <<
" mid_time=" << mid_time <<
" phi_off=" << pad_off/mOuterRadius <<
" time_off=" << time_off << endm;
254 for(current_sub_hit=-n_sub_hits; current_sub_hit <= n_sub_hits; current_sub_hit++)
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);
264 ipad = WhichPad(phi,isec);
266 LOG_DEBUG << current_sub_hit <<
"th subhit at time " << time <<
" phi " << phi <<
" => padpos " << mOuterRadius*phi <<
" ipad = "<<ipad <<endm;
272 int pad_min = WhichPad(phi-width_phi,isec_min);
273 int pad_max = WhichPad(phi+width_phi,isec_max);
275 if ( isec_min > isec_max )
276 nsecs = mDb->numberOfSectors() - isec_min + isec_max + 1;
278 if (isec_min == isec_max && pad_min >= pad_max )
279 nsecs = mDb->numberOfSectors() + 1;
281 nsecs = isec_max - isec_min + 1;
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;
288 npad = (pad_max - pad_min + 1);
289 float* pad =
new float[npad];
292 float dphi = fmod(phi-phiMin+twopi,twopi);
293 dphi = dphi - isec*(phiMax-phiMin);
295 for (i=0; i<npad; ++i ) {
296 float phi_low = PhiOfPad(i+pad_min,0) - 0.5*delta_phi;
298 float phi_up = PhiOfPad(i+pad_min,0) + 0.5*delta_phi;
300 pad[i] = InteGauss(mOuterRadius*phi_low, mOuterRadius*phi_up,
301 mOuterRadius*dphi, sigmaPadCentimeters );
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;
318 time = time - mDb->timeOffset(GetHardSec(isec, irow)*mDb->numberOfPads()+GetHardPad(isec,ipad,irow)+1, irow)/(0.001/mDb->microsecondsPerTimebin());
321 LOG_DEBUG <<
" to " << time <<
" for Sec "<< isec<<
" ("<<GetHardSec(isec, irow)<<
") pad "<< (ipad) <<
" ("<<GetHardPad(isec,ipad,irow)<<
") row " << irow <<endm;
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);
329 float* sca =
new float[ntim];
331 for (j=0; j<ntim; ++j) {
332 float tim_low = TimeOfSlice(j+tim_min)
335 float tim_up = TimeOfSlice(j+tim_min)
339 sca[j] = InteGauss(tim_low, tim_up, time, sigma_tim);
345 LOG_DEBUG << current_sub_hit <<
"th subhit from time " << tim_min <<
" to " << tim_min+ntim <<
" pad " << pad_min <<
" to " << pad_min+npad << endm;
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);
352 LOG_DEBUG <<
"Writing " << mADCArray[k] <<
" to pad "<< (i+pad_min)<<endm;
361 pad_max = pad_max_save;
363 if ( isec > mDb->numberOfSectors()-1 )
372 void StFtpcSlowSimReadout::OutputADC()
374 int num_pixels[11]={0}, num_pixels_occupied[11]={0};
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;
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;
389 if (mADCArray[i] != 0){
390 mADCArray[i] =(mADCArray[i] / mParam->adcConversion());
395 mADCArray[i] = mADCArray[i] - mDb->amplitudeOffset(GetHardSec(sec, row)*mDb->numberOfPads()+GetHardPad(sec,pad,row)+1, row);
397 LOG_DEBUG <<
"Using AmpSlope :" << mDb->amplitudeSlope(GetHardSec(sec, row)*mDb->numberOfPads()+GetHardPad(sec,pad,row)+1, row) <<endm;
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));
406 num_pixels[(int) (bin/30)]++;
409 mADCArray[i] += noise->GetRandom();
411 if(mADCArray[i] >= mParam->zeroSuppressThreshold()) {
415 num_pixels_occupied[(int) (bin/30)]++;
417 if (mADCArray[i] >= mMaxAdc)
418 mADCArray[i] = mMaxAdc;
426 LOG_DEBUG <<
"Occupancies:" << endm;
427 for(
int lastloop=0; lastloop<11;lastloop++)
429 if(num_pixels[lastloop]>0) {
430 LOG_DEBUG <<
"bin " << lastloop <<
" has occupancy" << num_pixels_occupied[lastloop]/(float) num_pixels[lastloop] << endm;
439 float StFtpcSlowSimReadout::PhiOfPad(
const int pad,
const int deg_or_rad)
441 return (pad+0.5)*mDb->radiansPerPad() + mDb->radiansPerBoundary()/2;
444 int StFtpcSlowSimReadout::WhichPad(
const float phi,
int &isec)
447 float dphi = fmod(phi-phiMin+twopi,twopi);
448 isec = (int)(dphi/(phiMax-phiMin));
451 if (isec == 6) isec = 0;
452 dphi = dphi - isec*(phiMax-phiMin)- mDb->radiansPerBoundary()/2;
453 int ipad = (int) (dphi/mDb->radiansPerPad());
457 if (ipad > mDb->numberOfPads() - 1) {
458 ipad = mDb->numberOfPads() - 1;
464 int StFtpcSlowSimReadout::WhichSlice(
const float time)
466 int itim = (int) (time*0.001/mDb->microsecondsPerTimebin()) ;
470 if (itim > mDb->numberOfTimebins() - 1) {
471 itim = mDb->numberOfTimebins() - 1;
476 float StFtpcSlowSimReadout::TimeOfSlice(
const int sslice)
478 return (sslice+0.5)*1000*mDb->microsecondsPerTimebin();
481 int StFtpcSlowSimReadout::GetHardPad(
const int daqsec,
const int daqpad,
const int irow)
488 if (pad > (mDb->numberOfPads() -1)) pad = mDb->numberOfPads() -1;
490 if (mDb->Asic2EastNotInverted() && (pad>63)&&(pad<96))
493 return (mDb->numberOfPads()-pad-1);
495 return (mDb->numberOfPads()-pad-1);
500 int StFtpcSlowSimReadout::GetHardSec(
const int daqsec,
const int irow)
503 if (sec < 0) sec = 0;
504 if (sec > (mDb->numberOfSectors() -1 )) sec = mDb->numberOfSectors() -1;
509 return (mDb->numberOfSectors()-sec-1);
512 void StFtpcSlowSimReadout::Print()
const
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 = "
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;
534 void StFtpcSlowSimReadout::polya(
const int ggnch,
const float gglow,
535 const float gghigh,
const float ggdelta)
546 float c_polya = 1.6925687;
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 ;
558 for (i=0; i<ggnch; ++i) {
559 pcum[i] /= pcum[ggnch-1];
564 int StFtpcSlowSimReadout::sample_polya(
const float gain)
568 if (mRandomNumberGenerator == 0)
570 ran = gRandom->Rndm();
577 int ich = Locate(gnch, pcum, ran);
579 return (
int) ( gain * ( glow + ich * gdelta ) );
583 float StFtpcSlowSimReadout::InteGauss(
const float x_1,
const float x_2,
584 const float x_0,
const float sig)
592 x = x2; x2 = x1; x1 = x;
595 float del_x = (x2-x1)/((
float) (mGaussIntSteps-1) );
600 for(
int i=0; i<(mGaussIntSteps-1); ++i ) {
601 sum += exp(-0.5*x*x);
605 return del_x*0.39894228*sum;
608 float StFtpcSlowSimReadout::ranmar()
625 cd = (float) 7654321./(
float)16777216.;
626 cm = (float)16777213./(
float)16777216.;
630 uni = uc.u[i-1] - uc.u[j-1];
631 if (uni < (
float)0.0) uni += (float)1.0;
642 if (uc.c < (
float)0.0) uc.c += cm;
645 if (uni < (
float)0.0) uni += (float) 1.0;
650 void StFtpcSlowSimReadout::rmarin(
int ij,
int kl)
667 i = (ij/177) % 177 + 2;
669 k = (kl/169) % 178 + 1;
672 LOG_DEBUG <<
"Ranmar initialized:" << ij <<
" "
679 for(ii=0; ii<97; ii++) {
684 for(jj=0; jj<24; jj++) {
686 m = ( (i*j) % 179 )*k % 179;
692 if ( (l*m)%64 >= 32 ) s += t;
701 uc.c = 362436./16777216.;