18 return std::min(std::max(n, 0L), emesh->
get_q() - 2);
22 const std::vector<double>& y) {
24 const long n = findInterval(emesh, x);
25 const double x1 = emesh->
get_ec(n);
26 const double x2 = emesh->
get_ec(n + 1);
27 const double y1 = y[n];
28 const double y2 = y[n + 1];
29 return y1 + (x - x1) * (y2 - y1) / (x2 - x1);
32double sample_ctheta(
const double sigma) {
35 double y = Heed::SRANLUX();
39 const double x = sigma * (-log(1.0 - y));
41 }
while (ctheta <= -1.0);
55using CLHEP::c_squared;
57bool HeedDeltaElectron::s_low_mult_scattering =
true;
58bool HeedDeltaElectron::s_high_mult_scattering =
true;
59bool HeedDeltaElectron::s_direct_low_if_little =
true;
63 long fparent_particle_number,
69 m_print_listing(fprint_listing) {
70 mfunname(
"HeedDeltaElectron::HeedDeltaElectron(...)");
74 mfunname(
"void HeedDeltaElectron::physics_mrange(double& fmrange)");
75 if (m_print_listing)
mcout <<
"HeedDeltaElectron::physics_mrange\n";
77 m_mult_low_path_length =
false;
78 m_q_low_path_length = 0.0;
79 m_path_length =
false;
80 if (fmrange <= 0.0)
return;
93 const double dedx = interpolate(emesh, ek, hdecs->eLoss);
95 double eloss = std::max(0.1 * ek, 0.00005);
100 m_stop_eloss =
false;
102 fmrange = std::min(fmrange, (eloss / dedx) * cm);
104 const double ek_restr = std::max(ek, 0.0005);
107 double low_path_length = 0.;
108 if (s_low_mult_scattering) {
109 low_path_length = interpolate(emesh, ek_restr, hdecs->low_lambda) * cm;
111 long qscat = hdecs->eesls->get_qscat();
112 const double sigma_ctheta = hdecs->get_sigma(ek_restr, qscat);
114 if (sigma_ctheta > 0.3) qscat = long(qscat * 0.3 / sigma_ctheta);
115 const double mult_low_path_length = qscat * low_path_length;
117 if (fmrange > mult_low_path_length) {
118 fmrange = mult_low_path_length;
119 m_mult_low_path_length =
true;
120 m_q_low_path_length = hdecs->eesls->get_qscat();
121 m_stop_eloss =
false;
123 m_mult_low_path_length =
false;
124 m_q_low_path_length = fmrange / low_path_length;
126 if (m_print_listing)
Iprint2nf(
mcout, fmrange, m_q_low_path_length);
129 if (s_high_mult_scattering) {
130 const double mean_path = interpolate(emesh, ek_restr, hdecs->lambda);
132 const double path_length = -mean_path * cm * log(1.0 - SRANLUX());
134 if (fmrange > path_length) {
135 fmrange = path_length;
136 m_path_length =
true;
137 m_mult_low_path_length =
true;
138 if (s_low_mult_scattering) {
139 m_q_low_path_length = fmrange / low_path_length;
142 m_stop_eloss =
false;
144 m_path_length =
false;
148 m_phys_mrange = fmrange;
152 std::vector<gparticle*>& ) {
153 mfunname(
"void HeedDeltaElectron::physics_after_new_speed()");
154 if (m_print_listing) {
155 mcout <<
"HeedDeltaElectron::physics_after_new_speed\n";
164 if (m_print_listing)
mcout <<
"Convert to conduction electron.\n";
170 if (m_print_listing)
mcout <<
"exit due to currpos.prange <= 0.0\n";
178 if (m_print_listing) {
185 if (m_stop_eloss && m_phys_mrange ==
m_currpos.prange) {
188 dedx = Eloss /
m_currpos.prange / (MeV / cm);
191 dedx = interpolate(emesh, ek, hdecs->eLoss);
193 m_total_eloss += Eloss;
199 if (m_print_listing)
mcout <<
"m_curr_ekin <= 0.0\n";
205 const double resten =
m_mass * c_squared;
211 if (m_print_listing) {
212 mcout <<
"volume is sensitive\n";
215 if (Eloss > 0.0) ionisation(Eloss, dedx, hdecs->pairprod);
217 if (m_print_listing) {
225 if (m_print_listing)
mcout <<
"Last conduction electron\n";
232 if (m_print_listing)
mcout <<
"\nstart to rotate by low angle\n";
233 double ek_restr = std::max(ek, 0.0005);
237 m_path_length =
false;
238 if (s_low_mult_scattering) {
240 const double low_path_length = interpolate(emesh, ek_restr, hdecs->low_lambda) * cm;
242 m_mult_low_path_length =
false;
243 m_q_low_path_length =
m_currpos.prange / low_path_length;
249 if (m_q_low_path_length > 0.0) {
250 m_q_low_path_length =
pois(m_q_low_path_length);
251 if (m_print_listing) {
252 mcout <<
"After pois:\n";
257 if (m_q_low_path_length > 0) {
258 if (s_direct_low_if_little && m_q_low_path_length < 5) {
260 if (m_print_listing) {
261 mcout <<
"direct modeling of low scatterings\n";
265 const long n1r = findInterval(emesh, ek_restr);
266 for (
long nscat = 0; nscat < m_q_low_path_length; ++nscat) {
269 hdecs->low_angular_points_ran[n1r].ran(SRANLUX()) * degree;
274 const double sigma = hdecs->get_sigma(ek_restr, m_q_low_path_length);
282 const double ctheta = sample_ctheta(sigma);
284 const double ctheta = sample_ctheta(sigma /
sqrt(2.));
287 const double theta =
acos(ctheta);
293 if (m_print_listing) {
294 mcout <<
"\nstarting to rotate by large angle" << std::endl;
298 const long n1r = findInterval(emesh, ek_restr);
299 const double theta = hdecs->angular_points_ran[n1r].ran(SRANLUX()) * degree;
306void HeedDeltaElectron::ionisation(
const double eloss,
const double dedx,
309 if (eloss < m_necessary_energy) {
310 m_necessary_energy -= eloss;
314 if (m_print_listing)
mcout <<
"\nstart to leave conduction electrons\n";
315 if (m_necessary_energy <= 0.0) {
319 m_necessary_energy = pairprod->
get_eloss() * eV;
322 if (m_print_listing)
Iprintnf(
mcout, m_necessary_energy / eV);
323 double eloss_left = eloss;
328 while (eloss_left >= m_necessary_energy) {
329 const double step_length = m_necessary_energy / (dedx * MeV / cm);
331 curpt = curpt + dir * step_length;
335 if (m_print_listing)
mcout <<
"New conduction electron\n";
340 eloss_left -= m_necessary_energy;
341 ekin -= m_necessary_energy;
342 if (ekin < 0.)
break;
345 m_necessary_energy = eV * pairprod->
get_eloss(ekin / eV);
347 m_necessary_energy = pairprod->
get_eloss() * eV;
349 if (m_print_listing) {
354 m_necessary_energy -= eloss_left;
355 if (m_print_listing)
Iprintnf(
mcout, m_necessary_energy / eV);
360 file <<
"HeedDeltaElectron: particle_number=" << m_particle_number <<
"\n";
362 file <<
" s_low_mult_scattering=" << s_low_mult_scattering
363 <<
" s_high_mult_scattering=" << s_high_mult_scattering <<
'\n'
364 <<
" phys_mrange=" << m_phys_mrange
365 <<
" stop_eloss=" << m_stop_eloss
366 <<
" mult_low_path_length=" << m_mult_low_path_length <<
'\n'
367 <<
" q_low_path_length=" << m_q_low_path_length
368 <<
" path_length=" << m_path_length
369 <<
" necessary_energy/eV=" << m_necessary_energy / eV <<
'\n'
#define check_econd11(a, signb, stream)
long get_q() const
Return number of bins.
double get_ec(long n) const
Return center of a given bin.
long get_interval_number_between_centers(const double ener) const
std::vector< HeedCondElectron > conduction_electrons
std::vector< HeedCondElectron > conduction_ions
long parent_particle_number
void physics_mrange(double &fmrange) override
void print(std::ostream &file, int l) const override
Print-out.
HeedDeltaElectron()=default
Default constructor.
void physics_after_new_speed(std::vector< gparticle * > &secondaries) override
Apply any other processes (turn the trajectory, kill the particle, ...).
Retrieve electric and magnetic field from Sensor.
double get_eloss() const
Calculate energy loss (in eV).
eparticle()=default
Default constructor.
HeedFieldMap * m_fieldMap
Pointer to field map.
stvpoint m_prevpos
Previous point.
void turn(const double ctheta, const double stheta)
Change the direction of the particle.
stvpoint m_currpos
Current point.
bool m_alive
Status flag whether the particle is active.
static std::atomic< long > s_counter
Instance counter.
Abstract base classs for volume "manipulators".
double m_prev_ekin
Previous kinetic energy.
double m_curr_ekin
Current kinetic energy.
void print(std::ostream &file, int l) const override
Print-out.
double m_curr_gamma_1
Current .
double m_mass
Mass (not mass * speed_of_light^2)
DoubleAc cos(const DoubleAc &f)
double lorbeta(const double gamma_1)
as function of .
particle_def electron_def("electron", "e-", electron_mass_c2/c_squared, electron_charge, 0.5)
DoubleAc acos(const DoubleAc &f)
long pois(const double amu)
DoubleAc sin(const DoubleAc &f)
DoubleAc sqrt(const DoubleAc &f)
#define Iprint3nf(file, name1, name2, name3)
#define Iprint3n(file, name1, name2, name3)
#define Iprint(file, name)
#define Iprintn(file, name)
#define Iprintf(file, name)
#define Iprint2nf(file, name1, name2)
#define Iprint2n(file, name1, name2)
#define Iprintnf(file, name)