StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
StTrsDeDx.cc
1 /*****************************************************************
2  *
3  * $Id: StTrsDeDx.cc,v 1.18 2012/06/11 15:04:56 fisyak Exp $
4  *
5  * Author: brian Nov 20, 1997
6  *
7  *****************************************************************
8  * Description: calculates dE/dx using a given parmeterization
9  * based on CERN/NA49 work. Cross checks in
10  * progress with GEANT, system test and P10 data
11  * He/C3H8 parameterization coming soon...
12  *
13  *****************************************************************
14  *
15  * $Log: StTrsDeDx.cc,v $
16  * Revision 1.18 2012/06/11 15:04:56 fisyak
17  * std namespace
18  *
19  * Revision 1.17 2009/09/28 18:36:14 perev
20  * Weird comparison fixed
21  *
22  * Revision 1.16 2004/05/03 23:31:12 perev
23  * Possible non init WarnOff
24  *
25  * Revision 1.15 2003/09/02 17:59:19 perev
26  * gcc 3.2 updates + WarnOff
27  *
28  * Revision 1.14 2000/06/07 02:03:11 lasiuk
29  * exit/abort ultimatum
30  *
31  * Revision 1.13 2000/01/10 23:14:30 lasiuk
32  * Include MACROS for compatiblity with SUN CC5
33  *
34  * Revision 1.12 1999/10/22 00:00:13 calderon
35  * -added macro to use Erf instead of erf if we have HP and Root together.
36  * -constructor with char* for StTrsDedx so solaris doesn't complain
37  * -remove mZeros from StTrsDigitalSector. This causes several files to
38  * be modified to conform to the new data format, so only mData remains,
39  * access functions change and digitization procedure is different.
40  *
41  * Revision 1.11 1999/07/20 02:19:58 lasiuk
42  * remove CVS merge conflicts
43  *
44  * Revision 1.10 1999/07/19 21:42:23 lasiuk
45  * - add tss bethe-bloche parameterization for P10. No saturation
46  * effects are included.
47  *
48  * Revision 1.9 1999/06/16 14:26:52 fisyak
49  * Add flags for egcs on Solaris
50  *
51  * Revision 1.8 1999/04/07 00:51:46 lasiuk
52  * refine diffusion coefficients for P10
53  *
54  * Revision 1.7 1999/03/17 17:11:30 lasiuk
55  * comment out debug output
56  *
57  * Revision 1.6 1999/01/26 20:43:29 lasiuk
58  * Jan 26
59  *
60  * Revision 1.5 1999/01/25 23:37:50 lasiuk
61  * sun string
62  *
63  * Revision 1.4 1999/01/23 18:47:23 fisyak
64  * Cleanup for SL98l
65  *
66  * Revision 1.3 1999/01/23 05:04:09 lasiuk
67  * provide a default constructor
68  *
69  * Revision 1.2 1999/01/15 10:57:45 lasiuk
70  * exponential dist
71  * unit check
72  *
73  * Revision 1.1 1998/11/10 17:12:24 fisyak
74  * Put Brian trs versin into StRoot
75  *
76  * Revision 1.9 1998/11/08 17:30:01 lasiuk
77  * allocators for SUN
78  *
79  * Revision 1.8 1998/11/02 22:48:21 lasiuk
80  * attachment coefficient as data member
81  *
82  * Revision 1.7 1998/11/01 17:37:45 lasiuk
83  * added diffusion coefficients (need them for transporter)
84  *
85  * Revision 1.6 1998/10/31 14:12:44 lasiuk
86  * add mMeanFreePath data member for nextInteraction member function;
87  * return energy in secondary member function;
88  * use SystemOfUnits in default padLength;
89  * name space considerations
90  *
91  * Revision 1.5 1998/10/22 14:56:30 lasiuk
92  * Incorporate 1/E^n distribution for primaries
93  *
94  * Revision 1.4 1998/10/22 00:24:22 lasiuk
95  * Oct 22
96  *
97  * Revision 1.3 1998/08/12 17:51:05 lasiuk
98  * incorporate units; update Bethe-Bloch
99  *
100  * Revision 1.2 1998/08/10 15:06:22 lasiuk
101  * random engine/distributions static
102  *
103  * Revision 1.1 1998/06/04 23:31:57 lasiuk
104  * Initial Revision
105  *
106  ******************************************************************/
107 #include <string.h>
108 #ifndef ST_NO_EXCEPTIONS
109 #include <stdexcept>
110 # if !defined(ST_NO_NAMESPACES)
111  using std::invalid_argument;
112 # endif
113 #endif
114 #include <math.h>
115 // SCL
116 #include "SystemOfUnits.h"
117 #include "PhysicalConstants.h"
118 
119 #ifndef ST_NO_NAMESPACES
120 using namespace units;
121 #endif
122 
123 #include "StTrsDeDx.hh"
124 
125 HepJamesRandom StTrsDeDx::mEngine;
126 RandFlat StTrsDeDx::mFlatDistribution(mEngine);
127 RandPoisson StTrsDeDx::mPoissonDistribution(mEngine);
128 RandExponential StTrsDeDx::mExponentialDistribution(mEngine);
129 
130 //static string trsDeDxDummy = "a";
131 
132 StTrsDeDx::StTrsDeDx()
133 {
134  mGas = "Ar";
135  mPadLength = 1.95*centimeter;
136  doInitialization();
137 }
138 StTrsDeDx::StTrsDeDx(const char* gas, double pad)
139  : mPadLength(pad)
140 {
141  mGas = gas;
142 //VP if((gas != "Ne") && (gas != "Ar") &&
143 //VP (gas != "P10") && (gas != "p10")) {
144  if (strcmp(gas, "Ne") && strcmp(gas,"Ar")
145  && strcmp(gas,"P10") && strcmp(gas,"p10")) {
146 #ifdef ST_USES_EXCEPTIONS
147  std::cerr << "oops" << endl;
148  throw invalid_argument("Gas not currently Implemented.\nMust use either \"Ne\" or \"Ar\" or \"P10\".");
149 #else
150  std::cerr << gas << " gas not currently Implemented." << endl;
151  std::cerr << "Must use either: \"Ne\", \"Ar\", or \"P10\"." << endl;
152  std::cerr << "Aborting..." << endl;
153  abort();
154 #endif
155  }
156  doInitialization();
157 }
158 StTrsDeDx::StTrsDeDx(const string& gas, double pad)
159  : mPadLength(pad)
160 {
161  mGas = gas;
162  if((gas != "Ne") && (gas != "Ar") &&
163  (gas != "P10") && (gas != "p10")) {
164 #ifdef ST_USES_EXCEPTIONS
165  std::cerr << "oops" << endl;
166  throw invalid_argument("Gas not currently Implemented.\nMust use either \"Ne\" or \"Ar\" or \"P10\".");
167 #else
168  std::cerr << gas.c_str() << " gas not currently Implemented." << endl;
169  std::cerr << "Must use either: \"Ne\", \"Ar\", or \"P10\"." << endl;
170  std::cerr << "Aborting..." << endl;
171  abort();
172 #endif
173  }
174  doInitialization();
175 }
176 
177 void StTrsDeDx::doInitialization()
178 {
179  mKonstant = 0.1536*MeV*centimeter2/gram;
180 
181  if(mGas == "Ne") {
182  mPairs = 12.4/centimeter; // in electrons/cm
183  mIonize = 21.6*eV;
184  mW = 36.6*eV;
185  mExponent = 2.2;
186 
187  // ??? same as P10 currently
188  mSigmaTransverse = 600*micrometer/::sqrt(centimeter);
189  mSigmaLongitudinal = 300*micrometer/::sqrt(centimeter);
190 
191  mDensity = 0.000839*gram/centimeter3;
192  mZa = .5; // Z/A
193  }
194 
195  if(mGas == "Ar") {
196  mPairs = 28.0/centimeter;
197  mIonize = 16.6*eV;
198  mW = 28.6*eV;
199  mExponent = 2.0;
200 
201  // ??? same as P10 currently
202  mSigmaTransverse = 600*micrometer/::sqrt(centimeter);
203  mSigmaLongitudinal = 300*micrometer/::sqrt(centimeter);
204 
205  mDensity = 0.00166*gram/centimeter3;
206  mZa = .45;
207  }
208 
209  if((mGas == "P10") || (mGas == "p10")) {
210  mPairs = 28.1/centimeter;
211  mIonize = 15.5*eV;
212  mW = 26.2*eV;
213  mExponent = 2.0;
214 
215  // ArCH4 (90:10) at 160 V/cm From Alber et al. NIM (NA49)
216  mSigmaTransverse = 633*micrometer/::sqrt(centimeter);
217  mSigmaLongitudinal = 370*micrometer/::sqrt(centimeter);
218 
219  // For P10 (see writeup)
220  mAttachment = 10.2/(1.e-6*second*bar*bar);//5.167e-4 per microsecond
221 
222  mDensity = 0.001561*gram/centimeter3;
223  mZa = .459;
224  }
225 
227  mAttachment = 10.2/(1.e-6*second*bar*bar);//5.167e-4 per microsecond
229 
230  // Common to all
231  mMeanFreePath = 1./mPairs;
232  mEReduced = 1 - mExponent;
233  mEE = ::pow(mIonize,mEReduced);
234  mEndPoint = 1000*mW;
235  mAlfat = mKonstant*gram/MeV/centimeter2*mZa*mPadLength/centimeter;
236 }
237 
238 StTrsDeDx::~StTrsDeDx() {/* nopt */}
239 
240 void StTrsDeDx::setPadLength(double len)
241 {
242  mPadLength = len;
243  mAlfat = mKonstant*gram/MeV/centimeter2*mZa*mPadLength/centimeter;
244 }
245 
246 double StTrsDeDx::nextInteraction() const
247 {
248  // determines scaler distance of next interaction
249  // according to mean free path
250  return mExponentialDistribution.shoot(mMeanFreePath);
251 }
252 
253 int StTrsDeDx::primary(double bg) const
254 {
255  int numberOfPrimaries;
256  if(bg == 1) {
257  numberOfPrimaries =
258  mPoissonDistribution.shoot(mPairs*mPadLength);
259  }
260  else {
261  numberOfPrimaries =
262  mPoissonDistribution.shoot(mPairs*mPadLength*betheBloch(bg));
263  }
264  return numberOfPrimaries;
265 }
266 
267 int StTrsDeDx::secondary(double* primaryEnergy) const
268 {
269  // Determined from the Energy distribution of the Primary Electrons
270  // Generate a 1/E^n distribution where n is (mExponent)
271 
272  double energyDistribution =
273  mFlatDistribution.shoot()*(mEE - ::pow(mEndPoint,mEReduced));
274 
275  *primaryEnergy =
276  ::pow(mEE - energyDistribution,(1/mEReduced));
277 
278  double numberOfSecondaries = (*primaryEnergy - mIonize)/mW;
279 
280  // Keep a Physical Limit on the number of secondaries that is possible
281  if(numberOfSecondaries > 1000)
282  numberOfSecondaries = 1000;
283 
284  return (static_cast<int>(numberOfSecondaries));
285 }
286 
287 #ifndef ST_NO_TEMPLATE_DEF_ARGS
288 void StTrsDeDx::electrons(vector<int>& sum, double bg) const
289 #else
290 void StTrsDeDx::electrons(vector<int, allocator<int> >& sum, double bg) const
291 #endif
292 {
293  //PR(StTrsDeDx::numberOfElectrons);
294  if(sum.size() != StTrsDeDx::numberOfElectrons)
295  sum.resize(StTrsDeDx::numberOfElectrons);
296  //PR(sum.size());
297  //copy(sum.begin(),sum.end()-1,ostream_iterator<int>(cout,","));
298  // define number of primaries
299  sum[StTrsDeDx::primaries] = this->primary(bg);
300 
301  //loop over primaries
302  double primaryEnergy;
303  sum[StTrsDeDx::secondaries] = 0;
304  for(int ii=0; ii<sum[StTrsDeDx::primaries]; ii++) {
305  sum[StTrsDeDx::secondaries] += this->secondary(&primaryEnergy);
306  }
307 
308  sum[StTrsDeDx::total] =
309  sum[StTrsDeDx::primaries] + sum[StTrsDeDx::secondaries];
310 }
311 
312 double StTrsDeDx::betheBloch(double bg) const
313 {
314  //
315  // Plateau Parameterization
316  // -- in general a function of the gas; and may have
317  // to be implemented as data members initialized
318  // in the constructor.
319 
320  // first corner
321  double x0 = .426266;
322 
323  // plateau
324  double x1 = 4.;
325 
326  // shape of rise
327  double m = 2.5;
328 
329  double xa=::log(1.649*mIonize/eV/(28.8*::sqrt(mDensity*centimeter3/gram*mZa)));
330 
331  double f = 4.606*(xa-x0)/(::pow((x1-x0),m));
332 
333  double bigx = ::log(bg)/::log(10.);
334 
335  // Saturation term
336  double d=-999999.;
337  if (bigx<x0)
338  d=0;
339  else if ((bigx>x0) && (bigx<x1))
340  d=4.606*(bigx-xa)+f*(::pow((x1-bigx),m));
341  else if(bigx>x1)
342  d=4.606*(bigx-xa);
343 
344  // Bethe-Bloch Parameterization:
345  double k=.891;
346 
347  // Compute the minimum
348  double bgMin = 3.;
349  double te = k + 2*::log(bgMin) - (sqr(bgMin)/(sqr(bgMin)+1)) - ::log(sqr(bgMin)/(sqr(bgMin)+1));
350  double Io = mAlfat*((sqr(bgMin)+1)/sqr(bgMin))*(::log((electron_mass_c2/MeV*mAlfat)/(sqr(mIonize)))+te);
351 
352  te = k + 2*::log(bg) - (sqr(bg)/(sqr(bg)+1)) - ::log(sqr(bg)/(sqr(bg)+1)) - d;
353  double I = mAlfat*((sqr(bg)+1)/sqr(bg))*(::log((electron_mass_c2/MeV*mAlfat)/(sqr(mIonize)))+te);
354 
355  return (I/Io);
356 }
357 
358 double StTrsDeDx::betheBlochTSS(double p, double z, double m)
359 {
360  //
361  // Modified Bethe-Bloch formula, accounting for restricted energy loss.
362  // Form taken from PDG.
363  // The density effect correction term "delta" is not accounted for here.
364  // This should affect the relativistic rise.
365  // p = momentum (GeV/c)
366  // z = charge (e-)
367  // m = mass (GeV/c^2) of particle
368  //float beta,gamma; // ! relativistic velocity of particle
369 
370  double K = 0.3071*MeV/(gram/centimeter2);
371  double me = 511.*keV; // electron mass
372  double emax = 50.*keV; // cut-off energy (usually some 10s of keV)
373 
374  //
375  // Gas characteristics----------
376  const int ncomp=2;
377  double rhoP10 = 1.547e-3*gram/centimeter3; // P10 density
378  double rhocomp[ncomp] = {1.66e-3*gram/centimeter3,
379  6.70e-4*gram/centimeter3}; // Ar. CH4 density
380  double Acomp[ncomp] = {39.95*gram/mole, 16.04*gram/mole};
381  double Zcomp[ncomp] = {18.0, 10.0}; // A,Z of the two components in P10
382  double I[ncomp] = {188.0*eV, 41.7*eV}; // Mean excitation energy for
383  // components of P10
384  double dedxComp[ncomp]; // dedx for this component
385 
386  double percentage[ncomp] = {90.0, 10.0};
387 
388  double energy = ::sqrt(p*p+m*m);
389  double beta = p/energy;
390  double beta2 = beta*beta;
391  double gamma = energy/m;
392  double z2 = z*z;
393 
394  double weight, prefactor, arg;
395  for(int icomp=0; icomp<ncomp; icomp++) {
396  weight =
397  (percentage[icomp]*Acomp[icomp]/(percentage[0]*Acomp[0]+percentage[1]*Acomp[1]));
398  prefactor =
399  K*z2*Zcomp[icomp]/(Acomp[icomp]/(gram/mole)*beta2)*rhocomp[icomp];
400 
401  arg = beta*gamma*::sqrt(2.*me*emax)/I[icomp];
402  dedxComp[icomp] =
403  (weight/rhocomp[icomp])*prefactor*(::log(arg)-beta2/2.);
404  }
405 
406  return (rhoP10*(dedxComp[0] + dedxComp[1]));
407 }
408 
409 void StTrsDeDx::print(ostream& os) const
410 {
411  os << "=========== StTrsDeDx ================" << endl;
412 #if defined(__sun) && ! defined(__GNUG__)
413  os << "==> " << mGas.c_str() << endl;
414 #else
415  os << "==> " << mGas << endl;
416 #endif
417  os << "mPairs " << (mPairs*centimeter) << " /cm" << endl;
418  os << "mIonize " << (mIonize/eV) << " eV" << endl;
419  os << "mW " << (mW/eV) << " eV" << endl;
420  os << "mEndPoint " << (mEndPoint/keV) << " keV" << endl;
421  os << "mExponent " << (mExponent) << endl;
422  os << "mZa " << mZa << endl;
423  os << "--------------------------------------" << endl;
424  os << "mPadLength " << (mPadLength/centimeter) << " cm" << endl;
425  os << "======================================\n" << endl;
426 }