25 if (particle !=
"electron" && particle !=
"e" && particle !=
"e-") {
26 std::cerr <<
m_className <<
"::SetParticle: Only electrons are allowed.\n";
31 const double t0,
const double dx0,
32 const double dy0,
const double dz0) {
38 std::cerr <<
m_className <<
"::NewTrack: Sensor is not defined.\n";
46 <<
" No ionisable gas medium at initial position.\n";
49 std::vector<Parameters> par;
50 std::vector<double> frac;
51 if (!Setup(medium, par, frac)) {
53 <<
" Properties of " << medium->
GetName()
54 <<
" are not implemented.\n";
58 const std::string mediumName = medium->
GetName();
61 const size_t nComponents = frac.size();
62 std::vector<double> prob(nComponents, 0.);
63 double mfp = 0., dedx = 0.;
64 if (!Update(density,
m_beta2, par, frac, prob, mfp, dedx)) {
66 <<
" Cross-sections could not be calculated.\n";
79 const double d = sqrt(dx * dx + dy * dy + dz * dz);
84 const double scale = 1. / d;
89 const double dt = 1. / (sqrt(
m_beta2) * SpeedOfLight);
90 double e0 = ElectronMass * (sqrt(1. / (1. -
m_beta2)) - 1.);
99 medium =
m_sensor->GetMedium(x, y, z);
101 medium->
GetName() != mediumName ||
111 for (
size_t i = 0; i < nComponents; ++i) {
112 if (r > prob[i])
continue;
115 cluster.
esec = Esec(e0, par[i]);
116 m_clusters.push_back(std::move(cluster));
120 m_cluster = m_clusters.size() + 2;
125 int& ne,
double& ec,
double& extra) {
126 xc = yc = zc = tc = ec = extra = 0.;
128 if (m_clusters.empty())
return false;
130 if (m_cluster < m_clusters.size()) {
132 }
else if (m_cluster > m_clusters.size()) {
135 if (m_cluster >= m_clusters.size())
return false;
137 xc = m_clusters[m_cluster].x;
138 yc = m_clusters[m_cluster].y;
139 zc = m_clusters[m_cluster].z;
140 tc = m_clusters[m_cluster].t;
141 ec = m_clusters[m_cluster].esec;
147 return m_mfp > 0. ? 1. / m_mfp : 0.;
154bool TrackElectron::Setup(
Medium* gas, std::vector<Parameters>& par,
155 std::vector<double>& frac) {
158 std::cerr <<
"TrackElectron::Setup: Medium is not defined.\n";
163 if (nComponents == 0) {
164 std::cerr <<
"TrackElectron::Setup: Composition is not defined.\n";
167 par.resize(nComponents);
168 frac.assign(nComponents, 0.);
173 for (
size_t i = 0; i < nComponents; ++i) {
174 std::string gasname =
"";
176 if (gasname ==
"CF4") {
185 par[i].wSplit = 19.5;
186 }
else if (gasname ==
"Ar") {
191 par[i].cDens = 11.9480;
192 par[i].aDens = 0.19714;
193 par[i].mDens = 2.9618;
194 par[i].ethr = 15.75961;
196 }
else if (gasname ==
"He") {
201 par[i].cDens = 11.1393;
202 par[i].aDens = 0.13443;
203 par[i].mDens = 5.8347;
204 par[i].ethr = 24.58739;
205 par[i].wSplit = 10.5;
206 }
else if (gasname ==
"He-3") {
211 par[i].cDens = 11.1393;
212 par[i].aDens = 0.13443;
213 par[i].mDens = 5.8347;
214 par[i].ethr = 24.58739;
215 par[i].wSplit = 10.5;
216 }
else if (gasname ==
"Ne") {
221 par[i].cDens = 11.9041;
222 par[i].aDens = 0.08064;
223 par[i].mDens = 3.5771;
224 par[i].ethr = 21.56454;
225 par[i].wSplit = 19.5;
226 }
else if (gasname ==
"Kr") {
231 par[i].cDens = 12.5115;
232 par[i].aDens = 0.07446;
233 par[i].mDens = 3.4051;
234 par[i].ethr = 13.996;
236 }
else if (gasname ==
"Xe") {
241 par[i].cDens = 12.7281;
242 par[i].aDens = 0.23314;
243 par[i].mDens = 2.7414;
244 par[i].ethr = 12.129843;
245 par[i].wSplit = 23.7;
246 }
else if (gasname ==
"CH4") {
251 par[i].cDens = 9.5243;
252 par[i].aDens = 0.09253;
253 par[i].mDens = 3.6257;
256 }
else if (gasname ==
"iC4H10") {
261 par[i].cDens = 8.5633;
262 par[i].aDens = 0.10852;
263 par[i].mDens = 3.4884;
266 }
else if (gasname ==
"CO2") {
271 par[i].aDens = 0.11768;
272 par[i].mDens = 3.3227;
273 par[i].ethr = 13.777;
275 }
else if (gasname ==
"N2") {
280 par[i].cDens = 10.5400;
281 par[i].aDens = 0.15349;
282 par[i].mDens = 3.2125;
283 par[i].ethr = 15.581;
284 par[i].wSplit = 13.8;
286 std::cerr <<
"TrackElectron::Setup: Parameters for "
287 << gasname <<
" are not implemented.\n";
294bool TrackElectron::Update(
const double density,
const double beta2,
295 const std::vector<Parameters>& par,
296 const std::vector<double>& frac,
297 std::vector<double>& prob,
298 double& mfp,
double& dedx) {
300 if (beta2 <= 0.)
return false;
301 const double lnBg2 = log(beta2 / (1. - beta2));
303 const double e0 = ElectronMass * (
sqrt(1. / (1. - beta2)) - 1.);
305 const double eta = density / LoschmidtNumber;
306 const double x = 0.5 * (lnBg2 + log(eta)) / log(10.);
308 const size_t n = par.size();
311 for (
size_t i = 0; i < n; ++i) {
312 const double delta = Delta(x, par[i]);
313 prob[i] =
frac[i] * (par[i].m2 * (lnBg2 - beta2 - delta) + par[i].cIon);
315 const double ew = (e0 - par[i].ethr) / (2 * par[i].wSplit);
316 const double emean = (par[i].wSplit / (2 * atan(ew))) * log1p(ew * ew);
317 dedx += prob[i] * emean;
320 const double psum = std::accumulate(prob.begin(), prob.end(), 0.);
322 std::cerr <<
"TrackElectron::Update: Total cross-section <= 0.";
325 const double scale = 1. / psum;
326 for (
size_t i = 0; i < n; ++i) {
328 if (i > 0) prob[i] += prob[i - 1];
331 constexpr double prefactor =
332 4 * Pi * HbarC * HbarC / (ElectronMass * ElectronMass);
333 const double cs = prefactor * psum / beta2;
334 mfp = 1. / (cs * density);
335 dedx *= density * prefactor / beta2;
339double TrackElectron::Delta(
const double x,
const Parameters& par) {
342 if (par.x0 < par.x1 && x >= par.x0) {
343 delta = 2 * log(10.) *
x - par.cDens;
345 delta += par.aDens *
pow(par.x1 - x, par.mDens);
351double TrackElectron::Esec(
const double e0,
const Parameters& par) {
352 double esec = par.wSplit * tan(
RndmUniform() * atan((e0 - par.ethr) /
354 return par.wSplit *
pow(esec / par.wSplit, 0.9524);
Abstract base class for media.
virtual void GetComponent(const unsigned int i, std::string &label, double &f)
Get the name and fraction of a given component.
virtual double GetNumberDensity() const
Get the number density [cm-3].
unsigned int GetNumberOfComponents() const
Get number of components of the medium.
const std::string & GetName() const
Get the medium name/identifier.
virtual bool IsGas() const
Is this medium a gas?
bool IsIonisable() const
Is charge deposition by charged particles/photon enabled in this medium?
void SetParticle(const std::string &particle) override
bool GetCluster(double &xc, double &yc, double &zc, double &tc, int &nc, double &ec, double &extra) override
bool NewTrack(const double x0, const double y0, const double z0, const double t0, const double dx0, const double dy0, const double dz0) override
double GetClusterDensity() override
double GetStoppingPower() override
Get the stopping power (mean energy loss [eV] per cm).
TrackElectron()
Constructor.
void SetBetaGamma(const double bg)
Set the relative momentum of the particle.
std::string m_particleName
Track()=delete
Default constructor.
double RndmUniform()
Draw a random number uniformly distributed in the range [0, 1).
void RndmDirection(double &dx, double &dy, double &dz, const double length=1.)
Draw a random (isotropic) direction vector.
double RndmUniformPos()
Draw a random number uniformly distributed in the range (0, 1).
DoubleAc pow(const DoubleAc &f, double p)
DoubleAc sqrt(const DoubleAc &f)