39 if (particle !=
"electron" && particle !=
"e" && particle !=
"e-") {
41 std::cerr <<
" Only electrons can be transported.\n";
46 const double t0,
const double dx0,
47 const double dy0,
const double dz0) {
54 std::cerr <<
" Sensor is not defined.\n";
62 std::cerr <<
" No medium at initial position.\n";
67 std::cerr <<
" Medium at initial position is not ionisable.\n";
72 if (!medium->
IsGas()) {
74 std::cerr <<
" Medium at initial position is not a gas.\n";
78 if (!SetupGas(medium)) {
80 std::cerr <<
" Properties of medium " << medium->
GetName()
81 <<
" are not available.\n";
85 if (!UpdateCrossSection()) {
87 std::cerr <<
" Cross-sections could not be calculated.\n";
91 m_mediumName = medium->
GetName();
97 const double dd = sqrt(dx0 * dx0 + dy0 * dy0 + dz0 * dz0);
101 std::cout <<
" Direction vector has zero norm.\n";
102 std::cout <<
" Initial direction is randomized.\n";
105 const double stheta = sqrt(1. - ctheta * ctheta);
107 m_dx = cos(phi) * stheta;
108 m_dy = sin(phi) * stheta;
122 double& tcls,
int& ncls,
double& edep,
132 <<
" Track not initialized. Call NewTrack first.\n";
141 m_t += d / (sqrt(
m_beta2) * SpeedOfLight);
154 if (medium->
GetName() != m_mediumName ||
166 const int nComponents = m_components.size();
167 for (
int i = 0; i < nComponents; ++i) {
176 const double e0 = ElectronMass * (sqrt(1. / (1. -
m_beta2)) - 1.);
177 double esec = m_components[iComponent].wSplit *
178 tan(
RndmUniform() * atan((e0 - m_components[iComponent].ethr) /
179 (2. * m_components[iComponent].wSplit)));
180 esec = m_components[iComponent].wSplit *
181 pow(esec / m_components[iComponent].wSplit, 0.9524);
182 m_electrons.resize(1);
183 m_electrons[0].energy = esec;
184 m_electrons[0].x = xcls;
185 m_electrons[0].y = ycls;
186 m_electrons[0].z = zcls;
197 std::cerr <<
m_className <<
"::GetClusterDensity:\n";
198 std::cerr <<
" Track has not been initialized.\n";
203 std::cerr <<
m_className <<
"::GetClusterDensity:\n";
204 std::cerr <<
" Mean free path is not available.\n";
214 std::cerr <<
m_className <<
"::GetStoppingPower:\n";
215 std::cerr <<
" Track has not been initialised.\n";
219 const double prefactor = 4 * Pi * pow(HbarC / ElectronMass, 2);
224 const double e0 = ElectronMass * (sqrt(1. / (1. -
m_beta2)) - 1.);
225 const int nComponents = m_components.size();
226 for (
int i = nComponents; i--;) {
229 m_mediumDensity * m_components[i].fraction * (prefactor /
m_beta2) *
230 (m_components[i].m2Ion * (lnBg2 -
m_beta2) + m_components[i].cIon);
231 const double ew = (e0 - m_components[i].ethr) / (2 * m_components[i].wSplit);
234 (m_components[i].wSplit / (2 * atan(ew))) * log(1. + ew * ew);
235 dedx += cmean * emean;
241bool TrackElectron::SetupGas(
Medium* gas) {
243 m_components.clear();
247 std::cerr <<
" Medium is not defined.\n";
253 if (nComponents <= 0) {
255 std::cerr <<
" Medium composition is not defined.\n";
258 m_components.resize(nComponents);
264 for (
int i = nComponents; i--;) {
265 std::string gasname =
"";
268 m_components[i].fraction =
frac;
269 m_components[i].p = 0.;
270 if (gasname ==
"CF4") {
271 m_components[i].m2Ion = 7.2;
272 m_components[i].cIon = 93.;
273 m_components[i].x0Dens = 1.;
274 m_components[i].x1Dens = 0.;
275 m_components[i].cDens = 0.;
276 m_components[i].aDens = 0.;
277 m_components[i].mDens = 0.;
278 m_components[i].ethr = 15.9;
279 m_components[i].wSplit = 19.5;
280 }
else if (gasname ==
"Ar") {
281 m_components[i].m2Ion = 3.593;
282 m_components[i].cIon = 39.7;
283 m_components[i].x0Dens = 1.7635;
284 m_components[i].x1Dens = 4.4855;
285 m_components[i].cDens = 11.9480;
286 m_components[i].aDens = 0.19714;
287 m_components[i].mDens = 2.9618;
288 m_components[i].ethr = 15.75961;
289 m_components[i].wSplit = 15.;
290 }
else if (gasname ==
"He") {
291 m_components[i].m2Ion = 0.489;
292 m_components[i].cIon = 5.5;
293 m_components[i].x0Dens = 2.2017;
294 m_components[i].x1Dens = 3.6122;
295 m_components[i].cDens = 11.1393;
296 m_components[i].aDens = 0.13443;
297 m_components[i].mDens = 5.8347;
298 m_components[i].ethr = 24.58739;
299 m_components[i].wSplit = 10.5;
300 }
else if (gasname ==
"He-3") {
301 m_components[i].m2Ion = 0.489;
302 m_components[i].cIon = 5.5;
303 m_components[i].x0Dens = 2.2017;
304 m_components[i].x1Dens = 3.6122;
305 m_components[i].cDens = 11.1393;
306 m_components[i].aDens = 0.13443;
307 m_components[i].mDens = 5.8347;
308 m_components[i].ethr = 24.58739;
309 m_components[i].wSplit = 10.5;
310 }
else if (gasname ==
"Ne") {
311 m_components[i].m2Ion = 1.69;
312 m_components[i].cIon = 17.8;
313 m_components[i].x0Dens = 2.0735;
314 m_components[i].x1Dens = 4.6421;
315 m_components[i].cDens = 11.9041;
316 m_components[i].aDens = 0.08064;
317 m_components[i].mDens = 3.5771;
318 m_components[i].ethr = 21.56454;
319 m_components[i].wSplit = 19.5;
320 }
else if (gasname ==
"Kr") {
321 m_components[i].m2Ion = 5.5;
322 m_components[i].cIon = 56.9;
323 m_components[i].x0Dens = 1.7158;
324 m_components[i].x1Dens = 5.0748;
325 m_components[i].cDens = 12.5115;
326 m_components[i].aDens = 0.07446;
327 m_components[i].mDens = 3.4051;
328 m_components[i].ethr = 13.996;
329 m_components[i].wSplit = 21.;
330 }
else if (gasname ==
"Xe") {
331 m_components[i].m2Ion = 8.04;
332 m_components[i].cIon = 75.25;
333 m_components[i].x0Dens = 1.5630;
334 m_components[i].x1Dens = 4.7371;
335 m_components[i].cDens = 12.7281;
336 m_components[i].aDens = 0.23314;
337 m_components[i].mDens = 2.7414;
338 m_components[i].ethr = 12.129843;
339 m_components[i].wSplit = 23.7;
340 }
else if (gasname ==
"CH4") {
341 m_components[i].m2Ion = 3.75;
342 m_components[i].cIon = 42.5;
343 m_components[i].x0Dens = 1.6263;
344 m_components[i].x1Dens = 3.9716;
345 m_components[i].cDens = 9.5243;
346 m_components[i].aDens = 0.09253;
347 m_components[i].mDens = 3.6257;
348 m_components[i].ethr = 12.65;
349 m_components[i].wSplit = 8.;
350 }
else if (gasname ==
"iC4H10") {
351 m_components[i].m2Ion = 15.5;
352 m_components[i].cIon = 160.;
353 m_components[i].x0Dens = 1.3788;
354 m_components[i].x1Dens = 3.7524;
355 m_components[i].cDens = 8.5633;
356 m_components[i].aDens = 0.10852;
357 m_components[i].mDens = 3.4884;
358 m_components[i].ethr = 10.67;
359 m_components[i].wSplit = 7.;
360 }
else if (gasname ==
"CO2") {
361 m_components[i].m2Ion = 5.6;
362 m_components[i].cIon = 57.91;
363 m_components[i].x0Dens = 1.6294;
364 m_components[i].x1Dens = 4.1825;
365 m_components[i].aDens = 0.11768;
366 m_components[i].mDens = 3.3227;
367 m_components[i].ethr = 13.777;
368 m_components[i].wSplit = 13.;
369 }
else if (gasname ==
"N2") {
370 m_components[i].m2Ion = 3.35;
371 m_components[i].cIon = 38.1;
372 m_components[i].x0Dens = 1.7378;
373 m_components[i].x1Dens = 4.1323;
374 m_components[i].cDens = 10.5400;
375 m_components[i].aDens = 0.15349;
376 m_components[i].mDens = 3.2125;
377 m_components[i].ethr = 15.581;
378 m_components[i].wSplit = 13.8;
381 std::cerr <<
" Cross-section for " << gasname
382 <<
" is not available.\n";
388 m_components.clear();
394bool TrackElectron::UpdateCrossSection() {
396 const double prefactor = 4 * Pi *
pow(HbarC / ElectronMass, 2);
399 const double eta = m_mediumDensity / LoschmidtNumber;
400 const double x = 0.5 * (lnBg2 + log(eta)) / log(10.);
402 const int nComponents = m_components.size();
403 for (
int i = nComponents; i--;) {
405 if (m_components[i].x0Dens < m_components[i].x1Dens &&
406 x >= m_components[i].x0Dens) {
407 delta = 2 * log(10.) * x - m_components[i].cDens;
408 if (x < m_components[i].x1Dens) {
409 delta += m_components[i].aDens *
410 pow(m_components[i].x1Dens - x, m_components[i].mDens);
413 const double cs = (m_components[i].fraction * prefactor /
m_beta2) *
414 (m_components[i].m2Ion * (lnBg2 -
m_beta2 - delta) +
415 m_components[i].cIon);
416 m_components[i].p = cs;
421 std::cerr <<
m_className <<
"::UpdateCrossSection:\n";
422 std::cerr <<
" Total cross-section <= 0.\n";
426 m_mfp = 1. / (csSum * m_mediumDensity);
428 for (
int i = 0; i < nComponents; ++i) {
429 m_components[i].p /= csSum;
430 if (i > 0) m_components[i].p += m_components[i - 1].p;
Abstract base class for media.
virtual void GetComponent(const unsigned int i, std::string &label, double &f)
virtual double GetNumberDensity() const
unsigned int GetNumberOfComponents() const
const std::string & GetName() const
virtual bool IsGas() const
bool IsInArea(const double x, const double y, const double z)
Check if a point is inside the user area.
bool GetMedium(const double x, const double y, const double z, Medium *&medium)
Get the medium at (x, y, z).
virtual void SetParticle(const std::string &particle)
Set the type of particle.
virtual double GetClusterDensity()
virtual bool NewTrack(const double x0, const double y0, const double z0, const double t0, const double dx0, const double dy0, const double dz0)
virtual bool GetCluster(double &xcls, double &ycls, double &zcls, double &tcls, int &ncls, double &ecls, double &extra)
virtual double GetStoppingPower()
Get the stopping power (mean energy loss [eV] per cm).
void SetBetaGamma(const double bg)
Set the relative momentum of the particle.
std::string m_particleName
double RndmUniform()
Draw a random number uniformly distributed in the range [0, 1).
double RndmUniformPos()
Draw a random number uniformly distributed in the range (0, 1).
DoubleAc pow(const DoubleAc &f, double p)