GEMC  1.8
Geant4 Monte-Carlo Framework
CND_hitprocess.cc
Go to the documentation of this file.
1 // %%%%%%%%%%
2 // G4 headers
3 // %%%%%%%%%%
4 #include "G4UnitsTable.hh"
5 #include "G4Poisson.hh"
6 #include "Randomize.hh"
7 
8 
9 // %%%%%%%%%%%%%
10 // gemc headers
11 // %%%%%%%%%%%%%
12 #include "CND_hitprocess.h"
13 
14 
16 {
17  string hd_msg = Opt.args["LOG_MSG"].args + " CND Hit Process " ;
18  double HIT_VERBOSITY = Opt.args["HIT_VERBOSITY"].arg;
19  PH_output out;
20  out.identity = aHit->GetId();
21  HCname = "CND Hit Process";
22 
23  // %%%%%%%%%%%%%%%%%%%
24  // Raw hit information
25  // %%%%%%%%%%%%%%%%%%%
26  int nsteps = aHit->GetPos().size();
27 
28  // Get Total Energy deposited
29  double Etot = 0;
30  vector<G4double> Edep = aHit->GetEdep();
31  for(int s=0; s<nsteps; s++) Etot = Etot + Edep[s];
32 
33  // Charge for each step
34  vector<int> charge = aHit->GetCharges();
35 
36  // average global, local positions of the hit
37  double x, y, z;
38  double lx, ly, lz;
39  x = y = z = lx = ly = lz = 0;
40  vector<G4ThreeVector> pos = aHit->GetPos();
41  vector<G4ThreeVector> Lpos = aHit->GetLPos();
42 
43  if(Etot>0)
44  for(int s=0; s<nsteps; s++)
45  {
46  x = x + pos[s].x()*Edep[s]/Etot;
47  y = y + pos[s].y()*Edep[s]/Etot;
48  z = z + pos[s].z()*Edep[s]/Etot;
49  lx = lx + Lpos[s].x()*Edep[s]/Etot;
50  ly = ly + Lpos[s].y()*Edep[s]/Etot;
51  lz = lz + Lpos[s].z()*Edep[s]/Etot;
52  }
53  else
54  {
55  x = pos[0].x();
56  y = pos[0].y();
57  z = pos[0].z();
58  lx = Lpos[0].x();
59  ly = Lpos[0].y();
60  lz = Lpos[0].z();
61  }
62 
63  // average time
64  double time = 0;
65  vector<G4double> times = aHit->GetTime();
66  for(int s=0; s<nsteps; s++) time = time + times[s]/nsteps;
67 
68  // cout << "\t Time: " << time << endl;
69 
70 
71  // Energy of the track
72  double Ene = aHit->GetE();
73 
74  out.raws.push_back(Etot);
75  out.raws.push_back(x);
76  out.raws.push_back(y);
77  out.raws.push_back(z);
78  out.raws.push_back(lx);
79  out.raws.push_back(ly);
80  out.raws.push_back(lz);
81  out.raws.push_back(time);
82  out.raws.push_back((double) aHit->GetPID());
83  out.raws.push_back(aHit->GetVert().getX());
84  out.raws.push_back(aHit->GetVert().getY());
85  out.raws.push_back(aHit->GetVert().getZ());
86  out.raws.push_back(Ene);
87  out.raws.push_back((double) aHit->GetmPID());
88  out.raws.push_back(aHit->GetmVert().getX());
89  out.raws.push_back(aHit->GetmVert().getY());
90  out.raws.push_back(aHit->GetmVert().getZ());
91 
92 
93  // %%%%%%%%%%%%
94  // Digitization
95  // %%%%%%%%%%%%
96  int layer = out.identity[0].id;
97  int paddle = out.identity[1].id;
98 
99 
100  // Digitization Parameters
101  double light_yield=10000/MeV; // number of optical photons pruced in the scintillator per MeV of deposited energy
102  double att_length=3*m; // light attenuation length
103  double sensor_surface=pow(2.5*cm,2)*pi; // area of photo sensor
104  double light_coll=sensor_surface/ // ratio of photo_sensor area over paddle section ~ light collection efficiency
105  ((aHit->GetDetector().dimensions[0]+
106  aHit->GetDetector().dimensions[1])*
107  2*aHit->GetDetector().dimensions[4]);
108  double sensor_qe=0.2; // photo sensor quantum efficiency
109  double sensor_gain=0.08; // gain of the photo sensor in pC/(#p.e.); it defines the conversion from photoelectrons to charge:
110  // for a pmt gain of 10^6, this factor is equal to 10^6*1.6*10^-19 C = 0.16 pC/(#p.e.)
111  // assuming the signals are split into two going to QDC and scriminators it becomes 0.08 pC/(#p.e.)
112  double adc_conv=10; // conversion factor from pC to ADC (typical sensitivy of CAEN VME QDC is of 0.1 pC/ch)
113  double adc_ped=0; // ADC Pedestal
114  double veff=16*cm/ns; // light velocity in scintillator
115  double u_veff=16*cm/ns; // light velocity in uturn connector material
116  double sigmaT=0.16*ns/sqrt(MeV); // time smearing factor (estimated from tests at Orsay)
117  // double sigmaT=0.2*ns; // time smearing factor
118  double tdc_conv=1/0.050/ns; // TDC conversion factor
119  double u_length = 8*cm; // Path length through the u-turn connector between paddles
120  double bend_loss = 0.5; // Factor of energy loss in the u-turn bit of the scintillator
121 
122 
123  // initialize ADC and TDC
124  double etotL = 0;
125  double etotR = 0;
126  double timeL = 0;
127  double timeR = 0;
128  int ADCL = 0;
129  int ADCR = 0;
130  int TDCL = 4096;
131  int TDCR = 4096;
132 
133  double etotB = 0; // signal propagating to backward end of paddle hit happened in
134  double etotF = 0; // signal propagating to forward end of the paddle the hit happened in, round u-turn and along neighbouring paddle
135  double timeB = 0;
136  double timeF = 0;
137  int ADCB = 0;
138  int ADCF = 0;
139  int TDCB = 4096;
140  int TDCF = 4096;
141 
142  // cout << "\n Detector dimensions: " << endl;
143  // for (int d = 0; d < 5; d++){
144  // cout << " Dimension " << d << ": " << aHit->GetDetector().dimensions[d] << endl;
145  // }
146 
147  // cout << "\t Paddle positions: " << aHit->GetDetector().pos[0] << ", " << aHit->GetDetector().pos[1] << ", " << aHit->GetDetector().pos[2] << endl;
148 
149  // Get the paddle length: in CND paddles are along y
150  double length = aHit->GetDetector().dimensions[2];
151 
152  // Get info about detector material to eveluate Birks effect
153 
154  vector<int> pids = aHit->GetPIDs();
155 
156  double birks_constant=aHit->GetDetector().GetLogical()->GetMaterial()->GetIonisation()->GetBirksConstant();
157 
158  // cout << " Birks constant is: " << birks_constant << endl;
159  // cout << aHit->GetDetector().GetLogical()->GetMaterial()->GetName() << endl;
160 
161 
162  int dum[4] = {0,0,0,0};
163 
164  if(Etot>0)
165  {
166 
167  // cout << "-------------------------------------------------------------------" << endl;
168 
169  for(int s=0; s<nsteps; s++)
170  {
171  // Distances from left, right
172  double dLeft = length + Lpos[s].y();
173  double dRight = length - Lpos[s].y();
174 
175  // Distances from forward, back PMT
176  double dBack = length + Lpos[s].y();
177  double dFwd = 3*length - Lpos[s].y();
178 
179  // cout << "\n Distances: " << endl;
180  //cout << "\t dLeft, dRight, dBack, dFwd: " << dLeft << ", " << dRight << ", " << dBack << ", " << dFwd << endl;
181 
182  // apply Birks effect
183  double stepl = 0.;
184 
185  if (s == 0){
186  stepl = sqrt(pow((Lpos[s+1].x() - Lpos[s].x()),2) + pow((Lpos[s+1].y() - Lpos[s].y()),2) + pow((Lpos[s+1].z() - Lpos[s].z()),2));
187  }
188  else {
189  stepl = sqrt(pow((Lpos[s].x() - Lpos[s-1].x()),2) + pow((Lpos[s].y() - Lpos[s-1].y()),2) + pow((Lpos[s].z() - Lpos[s-1].z()),2));
190  }
191 
192  double Edep_B = BirksAttenuation(Edep[s],stepl,charge[s],birks_constant);
193 
194  // cout << "\t Birks Effect: " << " Edep=" << Edep[s] << " StepL=" << stepl
195  // << " PID =" << pids[s] << " charge =" << charge[s] << " Edep_B=" << Edep_B << endl;
196 
197  if (light_coll > 1) light_coll = 1.; // To make sure you don't miraculously get more energy than you started with
198 
199  etotL = etotL + Edep_B/2 * exp(-dLeft/att_length) * light_coll;
200  etotR = etotR + Edep_B/2 * exp(-dRight/att_length) * light_coll;
201 
202  etotB = etotB + Edep_B/2 * exp(-dBack/att_length) * light_coll;
203  etotF = etotF + Edep_B/2 * exp(-dFwd/att_length) * bend_loss * light_coll;
204 
205  // cout << "step: " << s << " etotL, etotR, etotB, etotF: " << etotL << ", " << etotR << ", " << etotB << ", " << etotF << endl;
206 
207  // timeL= timeL + (times[s] + dLeft/veff) / nsteps;
208  // timeR= timeR + (times[s] + dRight/veff) / nsteps;
209 
210  if ((dum[0] == 0) && (etotL >= 0.)){
211  timeL = times[s] + dLeft/veff;
212  dum[0] = 1;
213  }
214  if ((dum[1] == 0) && (etotR >= 0.)){
215  timeR = times[s] + dRight/veff;
216  dum[1] = 1;
217  }
218 
219  if ((dum[2] == 0) && (etotB >= 0.)){
220  timeB = times[s] + dBack/veff;
221  dum[2] = 1;
222  }
223  if ((dum[3] == 0) && (etotF >= 0.)){
224  timeF = times[s] + dFwd/veff + u_length/u_veff;
225  dum[3] = 1;
226  }
227 
228  // cout << "\t timeL, timeR, timeB, timeF: " << timeL << ", " << timeR << ", " << timeB << ", " << timeF << endl;
229 
230  // cout << "\n Edep: " << Edep[s]/MeV << " time: " << times[s]/ns << " Lpos-x: "
231  // << Lpos[s].x()/cm << " Lpos-y: " << Lpos[s].y()/cm << " Lpos - z: " << Lpos[s].z()/cm << " pos-x: "
232  // << pos[s].x()/cm << " pos-y: " << pos[s].y()/cm << " pos-z: " << pos[s].z()/cm << " etotL: "
233  // << etotL/MeV << " etotR: " << etotR/MeV << " timeL: " << timeL/ns << " timeR: " << timeR/ns << endl;
234 
235  }
236 
237  // cout << "***********************" << endl;
238  // cout << "etotL, etotR, etotB, etotF: " << etotL << ", " << etotR << ", " << etotB << ", " << etotF << endl;
239  // cout << "timeL, timeR, timeB, timeF: " << timeL << ", " << timeR << ", " << timeB << ", " << timeF << endl;
240 
241 
242  TDCL=(int) ((timeL+G4RandGauss::shoot(0.,sigmaT/sqrt(etotL))) * tdc_conv);
243  TDCR=(int) ((timeR+G4RandGauss::shoot(0.,sigmaT/sqrt(etotR))) * tdc_conv);
244  if(TDCL<0) TDCL=0;
245  if(TDCR<0) TDCR=0;
246 
247  ADCL=(int) (G4Poisson(etotL*light_yield*sensor_qe)*sensor_gain*adc_conv + adc_ped);
248  ADCR=(int) (G4Poisson(etotR*light_yield*sensor_qe)*sensor_gain*adc_conv + adc_ped);
249 
250  TDCB=(int) ((timeB + G4RandGauss::shoot(0.,sigmaT/sqrt(etotB))) * tdc_conv);
251  TDCF=(int) ((timeF + G4RandGauss::shoot(0.,sigmaT/sqrt(etotF))) * tdc_conv);
252  if(TDCB<0) TDCB=0;
253  if(TDCF<0) TDCF=0;
254 
255  // cout << "time right: " << TDCR / tdc_conv << " time left: " << TDCL/tdc_conv << endl;
256  // cout << "time forward: " << TDCF/tdc_conv << " time backwards: " << TDCB/tdc_conv << endl;
257 
258  ADCB=(int) (G4Poisson(etotB*light_yield*sensor_qe)*sensor_gain*adc_conv + adc_ped);
259  ADCF=(int) (G4Poisson(etotF*light_yield*sensor_qe)*sensor_gain*adc_conv + adc_ped);
260 
261  //cout << "energy right: " << ADCR / (adc_conv*sensor_gain*sensor_qe*light_yield) << " E left: " << ADCL / (adc_conv*sensor_gain*sensor_qe*light_yield) << endl;
262  //cout << "energy forw: " << ADCF / (adc_conv*sensor_gain*sensor_qe*light_yield) << " E back: " << ADCB / (adc_conv*sensor_gain*sensor_qe*light_yield) << endl;
263 
264  //cout << " Light collection: " << light_coll << endl;
265 
266  } // closes (Etot > 0) loop
267 
268  // cout << "___________x________x__________x_____________x_____________" << endl;
269 
270  if(HIT_VERBOSITY>4) {
271 
272  cout << "WOOF woof WOOF woof WOOF woof WOOF woof WOOF!!!" << endl;
273 
274  cout << hd_msg << " layer: " << layer << ", paddle: " << paddle << " x=" << x/cm << " y=" << y/cm << " z=" << z/cm << endl;
275  cout << hd_msg << " Etot=" << Etot/MeV << " time=" << time/ns << endl;
276  cout << hd_msg << " TDCL=" << TDCL << " TDCR=" << TDCR << " ADCL=" << ADCL << " ADCR=" << ADCR << endl;
277  cout << hd_msg << " TDCB=" << TDCB << " TDCF=" << TDCF << " ADCB=" << ADCB << " ADCF=" << ADCF << endl;
278  }
279 
280  out.dgtz.push_back(layer);
281  out.dgtz.push_back(paddle);
282  out.dgtz.push_back(ADCL);
283  out.dgtz.push_back(ADCR);
284  out.dgtz.push_back(TDCL);
285  out.dgtz.push_back(TDCR);
286  out.dgtz.push_back(ADCB);
287  out.dgtz.push_back(ADCF);
288  out.dgtz.push_back(TDCB);
289  out.dgtz.push_back(TDCF);
290 
291  return out;
292 }
293 
294 
295 vector<identifier> CND_HitProcess :: ProcessID(vector<identifier> id, G4Step *step, detector Detector, gemc_opts Opt)
296 {
297  id[id.size()-1].id_sharing = 1;
298  return id;
299 }
300 
301 
302 
303 double CND_HitProcess::BirksAttenuation(double destep,double stepl,int charge,double birks)
304 {
305  //Example of Birk attenuation law in organic scintillators.
306  //adapted from Geant3 PHYS337. See MIN 80 (1970) 239-244
307  //
308  // Taken from GEANT4 examples advanced/amsEcal and extended/electromagnetic/TestEm3
309  //
310  double response = destep;
311  if (birks*destep*stepl*charge != 0.)
312  {
313  response = destep/(1. + birks*destep/stepl);
314  }
315  return response;
316 }
317 
318 
319 
G4LogicalVolume * GetLogical()
Returns Logical Volume pointer.
Definition: detector.h:93
G4ThreeVector GetVert()
Definition: MHit.h:72
vector< double > raws
Raw information.
Definition: MPHBaseClass.h:26
int GetPID()
Definition: MHit.h:107
int GetmPID()
Definition: MHit.h:122
vector< identifier > GetId()
Definition: MHit.h:96
string HCname
Hit Collection name.
Definition: MPHBaseClass.h:41
G4ThreeVector GetmVert()
Definition: MHit.h:127
PH_output ProcessHit(MHit *, gemc_opts)
Method to process the hit.
vector< identifier > identity
Identifier.
Definition: MPHBaseClass.h:28
vector< G4ThreeVector > GetLPos()
Definition: MHit.h:69
double pi
Definition: dc12geom.h:24
double GetE()
Definition: MHit.h:89
vector< G4ThreeVector > GetPos()
Definition: MHit.h:65
double BirksAttenuation(double, double, int, double)
Definition: MHit.h:29
vector< double > GetTime()
Definition: MHit.h:82
map< string, opts > args
Options map.
Definition: usage.h:68
vector< int > GetPIDs()
Definition: MHit.h:108
vector< identifier > ProcessID(vector< identifier >, G4Step *, detector, gemc_opts)
Method to calculate new identifier.
vector< double > dimensions
vector of dimensions. Size, units depends on solid type
Definition: detector.h:63
vector< double > GetEdep()
Definition: MHit.h:76
detector GetDetector()
Definition: MHit.h:101
vector< int > dgtz
Digitized information.
Definition: MPHBaseClass.h:27
vector< int > GetCharges()
Definition: MHit.h:112