EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EicTpcDigiHitProducer.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file EicTpcDigiHitProducer.cxx
1 //
2 // AYK (ayk@bnl.gov), 2013/06/12
3 //
4 // "Ideal" TPC digitization code
5 //
6 
7 #include <math.h>
8 #include <stdlib.h>
9 #include <assert.h>
10 
11 #include <TRandom3.h>
12 
13 #include <TpcGeoParData.h>
14 #include <EicTrackingDigiHit.h>
15 #include <EicTpcDigiHitProducer.h>
16 
17 using namespace std;
18 
19 #define _SQR_(arg) ((arg)*(arg))
20 
21 // -----------------------------------------------------------------------------------------------
22 
24 {
25  // Sanity check; digi parameters need to be assigned;
26  if (!digi->fTransverseDispersion || !digi->fLongitudinalDispersion ||
27  !digi->fLongitudinalIntrinsicResolution || !digi->fTransverseIntrinsicResolution ||
28  !digi->fGemVerticalPadSize)
29  {
30  std::cout << "-E- EicTpcDigiHitProducer::HandleHit(): part of digi parameters not assigned!" << std::endl;
31  return -1;
32  } //if
33 
34  //
35  // Figure out how many times this trajectory part crossed vertical pad
36  // radius; yes, it's a hack; do it better later; assume that 1) I have to
37  // create 1 hit per such a crossing, 2) resolutions are constant and given
38  // via command line, 3) may safely generate 3D hits at random locations
39  // along the trajectory line; also assume that there are no pathologic
40  // cases like crossing the same radius twice within a step;
41  //
42 
43  ULogicalIndex_t xy = mGptr->GeantMultiToLogicalIndex(point->GetMultiIndex());
44  const LogicalVolumeLookupTableEntry *node = mGptr->GetLookupTableNode(xy);
45 
46  // FIXME: just check these is not screw up here;
47  //assert(0);
48  //TVector3 lstart = node->MasterToLocal(point->GetPosIn());
49  //TVector3 lend = node->MasterToLocal(point->GetPosOut());
50  TVector3 lstart = MasterToLocal(node->mGeoMtx, point->GetPosIn());
51  TVector3 lend = MasterToLocal(node->mGeoMtx, point->GetPosOut());
52 
53  // TPC gas volume half-length in [cm]; NB: as of 2014/08/05 this is actually
54  // a quarter-length (so ~50cm);
55  double zLen = 0.1 * (dynamic_cast <const TpcGeoParData*>(mGptr))->mTotalGasVolumeLength/4.0;
56 
57  double rstart = sqrt(_SQR_(lstart[0]) + _SQR_(lstart[1]));
58  double rend = sqrt(_SQR_(lend [0]) + _SQR_(lend [1]));
59 
60  //printf("%f %f\n", rstart, digi->fGemVerticalPadSize);
61 
62  unsigned nstart = (int)floor(rstart/digi->fGemVerticalPadSize);
63  unsigned nend = (int)floor(rend /digi->fGemVerticalPadSize);
64  unsigned hnum = nstart >= nend ? nstart - nend : nend - nstart;
65  //printf("%d\n", hnum);
66 
67  // Well, this procedure is simplistic anyway; so assume, that 1) steps are reasonably
68  // small compared to track curvature, 2) pads are arranged in cirlces of radius N*digi->fGemVerticalPadSize,
69  // 3) hits need to be produced only if hnum!=0 and exactly in this quantity;
70  if (hnum)
71  {
72  // Simplify expressions below;
73  double x1 = lstart[0];
74  double y1 = lstart[1];
75  double x2 = lend [0];
76  double y2 = lend [1];
77  // Prepare to solve quadratic equation;
78  double A = _SQR_(x1-x2) + _SQR_(y1-y2);
79  double B = x2*(x1-x2) + y2*(y1-y2);
80  unsigned min = nstart < nend ? nstart : nend;
81 
82  for(unsigned iqq=0; iqq<hnum; iqq++)
83  {
84  double R = (min + iqq + 1)*digi->fGemVerticalPadSize;
85  double C = _SQR_(x2) + _SQR_(y2) - _SQR_(R);
86 
87  // Find 2 roots of quadratic equation (a*x1+(1-a)*x2)^2 + (a*y1+(1-a)*y2)^2 = R^2;
88  double det = _SQR_(B) - A*C;
89  assert(A && det);
90  double rr[2] = {(-B + sqrt(det))/A, (-B - sqrt(det))/A};
91 
92  // I'm interested in root(s) in the range [0..1] (see equation above); at least
93  // one should exist, otherwise "hnum" would be wrong; well, in fact there
94  // should be exactly one "proper" root; check on that later;
95  unsigned ok_counter = 0;
96  for(unsigned ir=0; ir<2; ir++)
97  {
98  double alfa = rr[ir];
99 
100  if (alfa >= 0 && alfa <= 1)
101  {
102  ok_counter++;
103 
104  // Calculate 3D hit point;
105  TVector3 local = alfa * lstart + (1 - alfa) * lend;
106 
107 #if _OLD_
108  // So then smear local coordinates; yes, smear Y-coordinate as well,
109  // assuming it can be calculated better than N*digi->fGemVerticalPadSize using several
110  // timing measurements; think later;
111  //TVector3 qResolution(digi->fTransverseIntrinsicResolution,
112  // digi->fTransverseIntrinsicResolution,
113  // digi->fLongitudinalIntrinsicResolution);
114  double qResolution[3] = {digi->fTransverseIntrinsicResolution,
115  digi->fTransverseIntrinsicResolution,
116  digi->fLongitudinalIntrinsicResolution};
117 
118  // Calculate drift distance and imitate extra dispersion contribution;
119  {
120  TVector3 driftCff(digi->fTransverseDispersion, digi->fTransverseDispersion,
121  digi->fLongitudinalDispersion);
122 
123  // As of 2014/08/05 both up- and downstread half-gas volumes are oriented
124  // properly -> max value of local[2] coordinate is at the pads location (endcap);
125  double driftDist = zLen - local[2];
126 
127  //printf("%f\n", driftDist);
128  //assert(driftDist >= 0.0);
129  if (driftDist < 0.0) driftDist = 0.0;
130 
131  for(int iq=0; iq<3; iq++)
132  qResolution[iq] = sqrt(_SQR_(qResolution[iq]) + _SQR_(driftCff[iq]*sqrt(driftDist)));
133  }
134 
135  for(int iq=0; iq<3; iq++)
136  {
137  // Convert [um] -> [cm];
138  qResolution[iq] /= 1E4;
139  local[iq] += gRandom->Gaus(0.0, qResolution[iq]);
140  } /*for iq*/
141  //printf("%f %f %f\n", local[0], local[1], local[2]);
142 
143  // Make FairHit happy; do not want to change the meaning of those variables;
144  //TVector3 global = node->LocalToMaster(local);
145  TVector3 global = LocalToMaster(node->mGeoMtx, local);
146 
147  // Create hit;
148  //assert(0);
149  //TVector3 u(1,0,0), v(0,1,0);
150  {
151  //double x[3] = {1,0,0}, y[3] = {0,1,0}, result[3];
152  //TVector3 u, v;
153 
154  //node->mGeoMtx->LocalToMasterVect(x, result);
155  //u.SetXYZ(x[0], x[1], x[2]);
156 
157  //node->mGeoMtx->LocalToMasterVect(y, result);
158  //v.SetXYZ(result[0], result[1], result[2]);
159 
160  //assert(0);
161  //new((*arr)[arr->GetEntriesFast()])
162  //EicTrackingDigiHitOrth2D(detName, point, kfNodeID, global, local, mSigma);
163  {
164  double locarr[3] = {local.X(), local.Y(), local.Z()};
165 
166  double qCovariance[3][3];
167  memset(qCovariance, 0x00, sizeof(qCovariance));
168  for(unsigned ip=0; ip<3; ip++)
169  qCovariance[ip][ip] = _SQR_(qResolution[ip]);
170 
171  new((*mDigiHitArray)[mDigiHitArray->GetEntriesFast()])
172  // FIXME: 'nd=0' is dummy here;
173  EicTrackingDigiHit3D(mDetName->Name(), point, global, locarr, qCovariance);
174  //qResolution);
175  }
176  }
177 #else
178  // So then smear local coordinates; coordinate along the pads is smeared uniformly
179  // based on pad height; may want to override this behavior and smear in a gaussian
180  // way using by-hand provided resolution;
181  double radialResolution = digi->fRadialIntrinsicResolution ?
182  digi->fRadialIntrinsicResolution : 1E4*digi->fGemVerticalPadSize/sqrt(12.);
183  double qResolution[3] = {radialResolution,
184  digi->fTransverseIntrinsicResolution,
185  digi->fLongitudinalIntrinsicResolution};
186  //printf("%f %f %f\n", qResolution[0], qResolution[1], qResolution[2]);
187 
188  // Calculate drift distance and imitate extra dispersion contribution;
189  {
190  TVector3 driftCff(digi->fTransverseDispersion, digi->fTransverseDispersion,
191  digi->fLongitudinalDispersion);
192 
193  // As of 2014/08/05 both up- and downstread half-gas volumes are oriented
194  // properly -> max value of local[2] coordinate is at the pads location (endcap);
195  double driftDist = zLen - local[2];
196 
197  //printf("%f\n", driftDist);
198  //assert(driftDist >= 0.0);
199  if (driftDist < 0.0) driftDist = 0.0;
200 
201  // So these will be gaussian resolution estimates in phi-aligned system;
202  for(int iq=0; iq<3; iq++)
203  qResolution[iq] = sqrt(_SQR_(qResolution[iq]) + _SQR_(driftCff[iq]*sqrt(driftDist)));
204 
205  // Convert [um] -> [cm];
206  for(int iq=0; iq<3; iq++)
207  qResolution[iq] /= 1E4;
208  }
209 
210  // Cook phi-aligned 3D vector, ...;
211  //double radius = sqrt(_SQR_(local[0]) + _SQR_(local[1]));
212  //double buffer[3] = {radius, 0.0, local[2]}, smeared[3];
213  double buffer[3] = {R, 0.0, local[2]}, smeared[3];
214 
215  // ... smear it, ...;
216  //for(int iq=0; iq<3; iq++)
217  // Well, this is not exactly clean; assume, that instead of having equidistant
218  // hit coordinates in radial direction I can smear uniformly the points where
219  // trajectory crosses concentric cirlces of N*<pad_size> radii; I suspect one
220  // can further improve radial coordinate accuracy by comparing amplitudes in
221  // neighboring rows; consider setRadialIntrinsicResolution() in digitization.C;
222  buffer[0] += digi->fRadialIntrinsicResolution ?
223  gRandom->Gaus(0.0, qResolution[0]) : digi->fGemVerticalPadSize * gRandom->Uniform(-0.5, 0.5);
224  for(int iq=1; iq<3; iq++)
225  buffer[iq] += gRandom->Gaus(0.0, qResolution[iq]);
226 
227  // ... rotate back to the vicinity of original local[] point;
228  {
229  double phi = atan2(local[1], local[0]);
230  double s = sin(phi), c = cos(phi);
231  double r[2][2] = {{c, -s}, {s, c}};
232 
233  memset(smeared, 0x00, sizeof(smeared));
234  for(unsigned ip=0; ip<2; ip++)
235  for(unsigned iq=0; iq<2; iq++)
236  smeared[ip] += r[ip][iq]*buffer[iq];
237  smeared[2] = buffer[2];
238  //printf("%f %f ... %f %f\n", local[0], smeared[0], local[1], smeared[1]);
239 
240  // Make FairHit happy; do not want to change the meaning of those variables;
241  TVector3 global = LocalToMaster(node->mGeoMtx, smeared);
242 
243  double qCovariance[3][3], qBuffer[2][2];
244  memset(qCovariance, 0x00, sizeof(qCovariance));
245  //for(unsigned ip=0; ip<3; ip++)
246  //qCovariance[ip][ip] = _SQR_(qResolution[ip]);
247  //#if _LATER_
248  memset(qBuffer, 0x00, sizeof(qBuffer));
249  for(unsigned ip=0; ip<2; ip++)
250  qBuffer[ip][ip] = _SQR_(qResolution[ip]);
251 
252  for(unsigned ip=0; ip<2; ip++)
253  for(unsigned iq=0; iq<2; iq++)
254  for(unsigned it=0; it<2; it++)
255  for(unsigned is=0; is<2; is++)
256  qCovariance[ip][is] += r[ip][iq] * qBuffer[iq][it] * r[is][it];
257  qCovariance[2][2] = _SQR_(qResolution[2]);
258  //#endif
259 
260  TVector3 vCoord(smeared);
261  new((*mDigiHitArray)[mDigiHitArray->GetEntriesFast()])
262  //EicTrackingDigiHit3D(mDetName->Name(), point, global, smeared, qCovariance);
263  EicTrackingDigiHit3D(mDetName->Name(), point, global, vCoord, qCovariance);
264  }
265 #endif
266  } /*if*/
267  } /*for ir*/
268 
269 #if _BACK_
270  assert(ok_counter == 1);
271 #endif
272  } /*for iq*/
273  } //if
274 
275  return 0;
276 } // EicTpcDigiHitProducer::HandleHit()
277 
278 // -----------------------------------------------------------------------------------------------
279 
281 {
282  // Yes, export always happens precisely to the path given via 'fileName' (no VMCWORKDIR
283  // expansion like in importTpcDigiParameters());
284  TFile fout(fileName, "RECREATE");
285 
286  if (!fout.IsOpen())
287  {
288  std::cout << "-E- EicTpcDigiHitProducer::exportTpcDigiParameters(): failed to open '" <<
289  fileName << "'!" << std::endl;
290  return -1;
291  } //if
292 
293  fout.WriteObject(digi, mDetName->Name() + "DigiParData");
294  fout.Close();
295 
296  return 0;
297 } // EicTpcDigiHitProducer::exportTpcDigiParameters()
298 
299 // -----------------------------------------------------------------------------------------------
300 
302 {
303  TString expandedFileName(fileName);
304 
305  // Correct path if needed;
306  if (!expandedFileName.BeginsWith("./") && !expandedFileName.BeginsWith("/"))
307  {
308  TString wrkDir = getenv("VMCWORKDIR");
309 
310  expandedFileName = wrkDir + "/input/" + expandedFileName;
311  } //if
312 
313  TFile fin(expandedFileName);
314 
315  if (!fin.IsOpen())
316  {
317  std::cout << "-E- EicTpcDigiHitProducer::importTpcDigiParameters(): failed to open '" <<
318  fileName << "'!" << std::endl;
319  return -1;
320  } //if
321 
322  //fout.WriteObject(digi, mDetName->Name() + "DigiParData");
323  fin.GetObject(mDetName->Name() + "DigiParData", digi); assert(digi);
324  fin.Close();
325 
326  return 0;
327 } // EicTpcDigiHitProducer::importTpcDigiParameters()
328 
329 // -----------------------------------------------------------------------------------------------
330 
332 {
333  // Damn std::cout, long live printf!;
334  printf("\n-I- TPC 'naive' digitization parameters:\n\n");
335  printf(" transverse dispersion : %7.2f [um]/sqrt(D[cm])\n", fTransverseDispersion);
336  printf(" longitudinal dispersion : %7.2f [um]/sqrt(D[cm])\n", fLongitudinalDispersion);
337  printf(" transverse intrinsic resolution : %7.2f [um]\n", fTransverseIntrinsicResolution);
338  printf(" longitudinal intrinsic resolution: %7.2f [um]\n", fLongitudinalIntrinsicResolution);
339  printf(" radial intrinsic resolution : %7.2f [um]\n", fRadialIntrinsicResolution);
340  printf(" GEM vertical pad size : %7.2f [cm]\n\n", fGemVerticalPadSize);
341 } // TpcDigiParData::Print()
342 
343 // -----------------------------------------------------------------------------------------------
344