1#include "Tracking/Digitization/SiStripDigitizer.h"
7#include "Tracking/Digitization/SiStripConstants.h"
9namespace tracking::digitization {
16static constexpr double KT_Q_300K = 0.025852;
27 double path_length)
const {
32 const double total_u = std::abs(path_length * local_dir[0]);
34 (max_step > 0.0) ?
static_cast<int>(std::ceil(total_u / max_step)) : 1;
39 const double kt_q = KT_Q_300K * params_.
temperature / 300.0;
44 double sigma_sq = 0.0;
46 if (vb > vd && vd > 0.0) {
47 const double cf = 2.0 * vd * d / t;
48 const double base = kt_q * t * t / vd;
55 const double v_sum = vb + vd;
56 const double denom = v_sum - cf;
58 sigma_sq = base * std::log(v_sum / denom);
65 const double delta_v = vb - vd;
67 sigma_sq = base * std::log(1.0 + cf / delta_v);
70 }
else if (vb > 0.0) {
73 sigma_sq = 2.0 * kt_q * d * t / vb;
76 return std::sqrt(std::max(sigma_sq, 0.0));
84 const double inv_sqrt2_sigma = 1.0 / (std::sqrt(2.0) * sigma);
85 const double lo = (strip_center - 0.5 * pitch - u0) * inv_sqrt2_sigma;
86 const double hi = (strip_center + 0.5 * pitch - u0) * inv_sqrt2_sigma;
87 return 0.5 * (std::erf(hi) - std::erf(lo));
91 double q_per_seg,
int n_seg,
const Acts::Vector3& local_pos,
92 const Acts::Vector3& local_dir,
double path_length,
double w_collect,
93 double lorentz_tan,
bool is_minority)
const {
95 const double inv_cos2 = 1.0 + lorentz_tan * lorentz_tan;
97 std::map<int, double> sense_charges;
99 for (
int iseg = 0; iseg < n_seg; ++iseg) {
101 const double f = (iseg + 0.5) / n_seg;
104 const Acts::Vector3 seg_pos =
105 local_pos + (f - 0.5) * path_length * local_dir;
107 const double u_seg = seg_pos[0];
108 const double w_seg = seg_pos[2];
112 std::max(0.0, std::min(params_.
thickness, std::abs(w_collect - w_seg)));
117 double q_seg = q_per_seg;
119 const double efficiency =
120 std::max(0.0, std::min(1.0, 1.0 - 10.0 * params_.
trapping * drift));
127 std::max(sigma_1d * std::sqrt(inv_cos2), 1.0e-4);
130 const double u_dest = u_seg + drift * lorentz_tan;
133 const int strip_lo =
static_cast<int>(
134 std::floor((u_dest - 5.0 * sigma) / params_.
sense_pitch));
135 const int strip_hi =
static_cast<int>(
136 std::ceil((u_dest + 5.0 * sigma) / params_.
sense_pitch));
138 for (
int istrip = strip_lo; istrip <= strip_hi; ++istrip) {
139 const double strip_center = istrip * params_.
sense_pitch;
143 sense_charges[istrip] += q_seg * frac;
148 return sense_charges;
152 const std::map<int, double>& sense_charges)
const {
154 std::max(1,
static_cast<int>(
158 std::map<int, double> readout_charges;
162 for (
const auto& [sense_strip, charge] : sense_charges) {
163 readout_charges[sense_strip + offset] +=
166 return readout_charges;
182 for (
const auto& [sense_strip, charge] : sense_charges) {
184 static_cast<int>(std::floor(
static_cast<double>(sense_strip) / ratio));
185 const int position_in_group = sense_strip - ratio * k;
186 const int r = k + offset;
188 if (position_in_group == 0) {
195 return readout_charges;
203 double edep,
const Acts::Vector3& local_pos,
const Acts::Vector3& local_dir,
204 double path_length)
const {
205 const double total_electrons = edep / ENERGY_PER_EHP_MEV;
207 const double q_per_seg = total_electrons / n_seg;
213 const bool electron_is_minority = !params_.
is_n_type;
214 const bool hole_is_minority = params_.
is_n_type;
216 std::map<int, double> readout_charges;
220 const double w_electron = +0.5 * params_.
thickness;
222 q_per_seg, n_seg, local_pos, local_dir, path_length, w_electron,
225 readout_charges[strip] += charge;
231 const double w_hole = -0.5 * params_.
thickness;
233 q_per_seg, n_seg, local_pos, local_dir, path_length, w_hole,
236 readout_charges[strip] += charge;
240 return readout_charges;
244 std::map<int, double>& strip_charges) {
249 for (
const auto& [strip, charge] : strip_charges) {
250 extra.insert(strip - 1);
251 extra.insert(strip + 1);
253 for (
int s : extra) {
254 strip_charges.emplace(s, 0.0);
258 for (
auto& [strip, charge] : strip_charges) {
263 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.