1#include "Tracking/Digitization/SiStripDigitizer.h"
6#include "Tracking/Digitization/SiStripConstants.h"
8namespace tracking::digitization {
15static constexpr double KT_Q_300K = 0.025852;
26 double path_length)
const {
31 const double total_u = std::abs(path_length * local_dir[0]);
33 (max_step > 0.0) ?
static_cast<int>(std::ceil(total_u / max_step)) : 1;
38 const double kt_q = KT_Q_300K * params_.
temperature / 300.0;
43 double sigma_sq = 0.0;
45 if (vb > vd && vd > 0.0) {
46 const double cf = 2.0 * vd * d / t;
47 const double base = kt_q * t * t / vd;
54 const double v_sum = vb + vd;
55 const double denom = v_sum - cf;
57 sigma_sq = base * std::log(v_sum / denom);
64 const double delta_v = vb - vd;
66 sigma_sq = base * std::log(1.0 + cf / delta_v);
69 }
else if (vb > 0.0) {
72 sigma_sq = 2.0 * kt_q * d * t / vb;
75 return std::sqrt(std::max(sigma_sq, 0.0));
83 const double inv_sqrt2_sigma = 1.0 / (std::sqrt(2.0) * sigma);
84 const double lo = (strip_center - 0.5 * pitch - u0) * inv_sqrt2_sigma;
85 const double hi = (strip_center + 0.5 * pitch - u0) * inv_sqrt2_sigma;
86 return 0.5 * (std::erf(hi) - std::erf(lo));
90 double q_per_seg,
int n_seg,
const Acts::Vector3& local_pos,
91 const Acts::Vector3& local_dir,
double path_length,
double w_collect,
92 double lorentz_tan,
bool is_minority)
const {
94 const double inv_cos2 = 1.0 + lorentz_tan * lorentz_tan;
96 std::map<int, double> sense_charges;
98 for (
int iseg = 0; iseg < n_seg; ++iseg) {
100 const double f = (iseg + 0.5) / n_seg;
103 const Acts::Vector3 seg_pos =
104 local_pos + (f - 0.5) * path_length * local_dir;
106 const double u_seg = seg_pos[0];
107 const double w_seg = seg_pos[2];
111 std::max(0.0, std::min(params_.
thickness, std::abs(w_collect - w_seg)));
116 double q_seg = q_per_seg;
118 const double efficiency =
119 std::max(0.0, std::min(1.0, 1.0 - 10.0 * params_.
trapping * drift));
126 std::max(sigma_1d * std::sqrt(inv_cos2), 1.0e-4);
129 const double u_dest = u_seg + drift * lorentz_tan;
132 const int strip_lo =
static_cast<int>(
133 std::floor((u_dest - 5.0 * sigma) / params_.
sense_pitch));
134 const int strip_hi =
static_cast<int>(
135 std::ceil((u_dest + 5.0 * sigma) / params_.
sense_pitch));
137 for (
int istrip = strip_lo; istrip <= strip_hi; ++istrip) {
138 const double strip_center = istrip * params_.
sense_pitch;
142 sense_charges[istrip] += q_seg * frac;
147 return sense_charges;
151 const std::map<int, double>& sense_charges)
const {
153 std::max(1,
static_cast<int>(
157 std::map<int, double> readout_charges;
161 for (
const auto& [sense_strip, charge] : sense_charges) {
162 readout_charges[sense_strip + offset] +=
165 return readout_charges;
181 for (
const auto& [sense_strip, charge] : sense_charges) {
183 static_cast<int>(std::floor(
static_cast<double>(sense_strip) / ratio));
184 const int position_in_group = sense_strip - ratio * k;
185 const int r = k + offset;
187 if (position_in_group == 0) {
194 return readout_charges;
202 double edep,
const Acts::Vector3& local_pos,
const Acts::Vector3& local_dir,
203 double path_length)
const {
204 const double total_electrons = edep / ENERGY_PER_EHP_MEV;
206 const double q_per_seg = total_electrons / n_seg;
212 const bool electron_is_minority = !params_.
is_n_type;
213 const bool hole_is_minority = params_.
is_n_type;
215 std::map<int, double> readout_charges;
219 const double w_electron = +0.5 * params_.
thickness;
221 q_per_seg, n_seg, local_pos, local_dir, path_length, w_electron,
224 readout_charges[strip] += charge;
230 const double w_hole = -0.5 * params_.
thickness;
232 q_per_seg, n_seg, local_pos, local_dir, path_length, w_hole,
235 readout_charges[strip] += charge;
239 return readout_charges;
243 std::map<int, double>& strip_charges) {
248 for (
const auto& [strip, charge] : strip_charges) {
249 extra.insert(strip - 1);
250 extra.insert(strip + 1);
252 for (
int s : extra) {
253 strip_charges.emplace(s, 0.0);
257 for (
auto& [strip, charge] : strip_charges) {
262 for (
auto it = strip_charges.begin(); it != strip_charges.end();) {
std::map< int, double > computeStripCharges(double edep, const Acts::Vector3 &local_pos, const Acts::Vector3 &local_dir, double path_length) const
Simulate charge collection for a single hit.
int adaptiveNSegments(const Acts::Vector3 &local_dir, double path_length) const
Number of track sub-segments, chosen adaptively so that the U displacement per segment does not excee...
double diffusionSigma(double d, bool is_minority) const
Diffusion sigma [mm] for carriers drifting distance d [mm].
double stripFraction(double u0, double sigma, double strip_center, double pitch) const
Fraction of a Gaussian charge cloud (centred at u0 with sigma sigma) collected by a strip of width pi...
void applyNoiseAndThreshold(std::map< int, double > &strip_charges)
Add Gaussian electronic noise to signal strips and their immediate neighbours, then remove strips bel...
std::map< int, double > senseToReadout(const std::map< int, double > &sense_charges) const
Sum sense-strip charges into readout-strip charges according to the AC-coupling ratio ratio = round(r...
std::map< int, double > computeCarrierCharges(double q_per_seg, int n_seg, const Acts::Vector3 &local_pos, const Acts::Vector3 &local_dir, double path_length, double w_collect, double lorentz_tan, bool is_minority) const
Simulate one carrier type and return the sense-strip charge map.
double electron_lorentz_tangent
tan(θ_Lorentz) for electrons. Sign encodes U-shift direction.
double threshold_electrons
Readout threshold [electrons]. Strips below this are suppressed.
double readout_pitch
Readout strip pitch [mm]. Must be an integer multiple of sense_pitch.
double sense_pitch
Sense (inner) electrode pitch [mm].
double hole_lorentz_tangent
tan(θ_Lorentz) for holes.
double noise_electrons
Electronic noise sigma [electrons ENC].
double thickness
Sensor thickness [mm]. Must be set from the geometry before use.
int n_readout_strips
Total number of readout strips.
double bias_voltage
Applied reverse-bias voltage [V].
double deposition_granularity
Adaptive segmentation granularity: max U-step as fraction of sense_pitch.
double trapping
Charge-trapping fraction lost per 100 µm of drift.
double temperature
Operating temperature [K].
bool hole_side_readout
Simulate and read out the hole-collection side (p-strips / backplane).
double readout_transfer_efficiency
AC-coupling transfer efficiency from a paired sense strip (physically under a readout strip,...
int n_segments_min
Minimum number of track sub-segments (used when the track is close to normal incidence so the adaptiv...
double sense_transfer_efficiency
AC-coupling transfer efficiency from an unpaired sense strip (between two readout strips,...
bool electron_side_readout
Simulate and read out the electron-collection side (n-strips).
double depletion_voltage
Full-depletion voltage [V].
bool is_n_type
true = n-type bulk; false = p-type bulk. LDMX (and HPS) use n-type bulk.