27 constexpr
double operator""_um(
long double length) {
return length * 1
e-4; }
28 constexpr
double operator""_um_inv(
long double length) {
return length * 1
e4; }
34 if (use_ineff_from_db_) {
36 theSiPixelGainCalibrationService_->setESObjects(es);
39 if (use_deadmodule_DB_) {
43 if (use_LorentzAngle_DB_) {
57 (conf.getParameter<
edm::
ParameterSet>(
"Pixel3DDigitizerAlgorithm").getParameter<double>(
"NPColumnRadius")) *
60 (conf.getParameter<
edm::
ParameterSet>(
"Pixel3DDigitizerAlgorithm").getParameter<double>(
"OhmicColumnRadius")) *
63 (conf.getParameter<
edm::
ParameterSet>(
"Pixel3DDigitizerAlgorithm").getParameter<double>(
"NPColumnGap")) *
69 <<
"Algorithm constructed \n"
70 <<
"Configuration parameters:\n"
85 double time =
hit.tof() - tCorr;
95 const std::pair<float, float>& half_pitch)
const {
114 const float& ncarriers,
116 const std::pair<float, float> hpitches,
122 const float max_migration_radius = 0.4_um;
129 if (
std::abs(
pos.x() - hpitches.first) < max_migration_radius) {
131 pitch = hpitches.first;
132 }
else if (
std::abs(
pos.y() - hpitches.second) < max_migration_radius) {
134 pitch = hpitches.second;
137 return std::vector<DigitizerUtility::EnergyDepositUnit>();
142 std::vector<DigitizerUtility::EnergyDepositUnit> migrated_charge;
145 const float diffusion_step = 0.1_um;
148 std::vector<float> pos_moving({
pos.x(),
pos.y(),
pos.z()});
150 std::function<std::vector<float>(
int)> do_step =
151 [&pos_moving, &u_drift, diffusion_step](
int i) -> std::vector<float> {
152 auto dd = u_drift(pos_moving[0], pos_moving[1]);
153 return std::vector<float>({
i * diffusion_step *
dd.x(),
i * diffusion_step *
dd.y(),
i * diffusion_step *
dd.z()});
156 LogDebug(
"Pixel3DDigitizerAlgorithm::diffusion")
157 <<
"\nMax. radius from the pixel edge to migrate charge: " << max_migration_radius * 1.0_um_inv <<
" [um]"
158 <<
"\nMigration axis: " << displ_ind
159 <<
"\n(super-)Charge distance to the pixel edge: " << (
pitch - pos_moving[displ_ind]) * 1.0_um_inv <<
" [um]";
162 const float distance0 = 300.0_um;
163 const float sigma0 = 3.4_um;
165 const float TOL = 1
e-6;
173 float current_carriers = ncarriers;
174 std::vector<float> newpos({pos_moving[0], pos_moving[1], pos_moving[2]});
175 float distance_edge = 0.0_um;
177 std::transform(pos_moving.begin(), pos_moving.end(), do_step(
i).begin(), pos_moving.begin(), std::plus<float>());
180 double sigma =
std::sqrt(
i * diffusion_step / distance0) * (distance0 /
thickness) * sigma0;
183 float migrated_e = current_carriers * (1.0 - std::erf(distance_edge / sigma));
185 LogDebug(
"(super-)charge diffusion") <<
"step-" <<
i <<
", Initial Ne= " << ncarriers <<
", "
186 <<
"r=(" << pos_moving[0] * 1.0_um_inv <<
", " << pos_moving[1] * 1.0_um_inv
187 <<
", " << pos_moving[2] * 1.0_um_inv <<
") [um], "
188 <<
"Migrated charge: " << migrated_e;
193 if ((migrated_e - TOL) < 1.0) {
197 current_carriers -= migrated_e;
202 std::vector<float> newpos(pos_moving);
204 newpos[displ_ind] += std::copysign(
N_SIGMA * sigma, newpos[displ_ind]);
209 }
while (
std::abs(distance_edge) < max_migration_radius);
211 return migrated_charge;
224 const std::vector<DigitizerUtility::EnergyDepositUnit>& ionization_points)
const {
225 return drift(
hit, pixdet, bfield, ionization_points,
true);
231 const std::vector<DigitizerUtility::EnergyDepositUnit>& ionization_points,
232 bool diffusion_activated)
const {
242 const auto half_pitch = std::make_pair<float, float>(
pitch.first * 0.5,
pitch.second * 0.5);
246 const float pix_rounding = 0.99;
249 const float max_radial_distance =
250 std::sqrt(half_pitch.first * half_pitch.first + half_pitch.second * half_pitch.second);
259 LogDebug(
"Pixel3DDigitizerAlgorithm::drift")
260 <<
"Pixel pitch:" <<
pitch.first * 1.0_um_inv <<
", " <<
pitch.second * 1.0_um_inv <<
" [um]";
265 const float theta = std::atan2(
y,
x);
269 std::vector<DigitizerUtility::SignalPoint> collection_points;
271 collection_points.reserve(ionization_points.size());
275 const float RAD_DAMAGE = 0.001;
277 for (
const auto& super_charge : ionization_points) {
286 current_pixel.first = std::clamp(current_pixel.first,
float(0.0), (
nrows - 1) + pix_rounding);
287 current_pixel.second = std::clamp(current_pixel.second,
float(0.0), (
ncolumns - 1) + pix_rounding);
289 const auto current_pixel_int = std::make_pair(std::floor(current_pixel.first), std::floor(current_pixel.second));
293 const auto relative_position_at_pc =
294 std::make_pair((current_pixel.first - current_pixel_int.first) *
pitch.first,
295 (current_pixel.second - current_pixel_int.second) *
pitch.second);
298 LocalPoint position_at_pc(relative_position_at_pc.first - center_proxy_cell.
x(),
299 relative_position_at_pc.second - center_proxy_cell.
y(),
300 super_charge.z() - center_proxy_cell.
z());
302 LogDebug(
"Pixel3DDigitizerAlgorithm::drift")
303 <<
"(super-)Charge\nlocal position: (" << super_charge.x() * 1.0_um_inv <<
", " << super_charge.y() * 1.0_um_inv
304 <<
", " << super_charge.z() * 1.0_um_inv <<
") [um]"
305 <<
"\nMeasurement Point (row,column) (" << current_pixel.first <<
", " << current_pixel.second <<
")"
306 <<
"\nProxy pixel-cell frame (centered at left-down corner): (" << relative_position_at_pc.first * 1.0_um_inv
307 <<
", " << relative_position_at_pc.second * 1.0_um_inv <<
") [um]"
308 <<
"\nProxy pixel-cell frame (centered at n-column): (" << position_at_pc.x() * 1.0_um_inv <<
", "
309 << position_at_pc.y() * 1.0_um_inv <<
") [um] "
310 <<
"\nNe=" << super_charge.energy() <<
" electrons";
314 LogDebug(
"Pixel3DDigitizerAlgorithm::drift") <<
"Remove charge, inside the n-column or p-column!!";
320 if (diffusion_activated) {
321 auto migrated_charges =
diffusion(position_at_pc, super_charge.energy(), drift_direction, half_pitch,
thickness);
323 for (
auto&
mc : migrated_charges) {
328 const float pixel_x = current_pixel_int.first + (
mc.x() + center_proxy_cell.
x()) /
pitch.first;
329 const float pixel_y = current_pixel_int.second + (
mc.y() + center_proxy_cell.
y()) /
pitch.second;
333 mc.migrate_position(
LocalPoint(lp.x(), lp.y(),
mc.z() + center_proxy_cell.
z()));
335 if (!migrated_charges.empty()) {
336 LogDebug(
"Pixel3DDigitizerAlgorithm::drift") <<
"****************"
337 <<
"MIGRATING (super-)charges"
338 <<
"****************";
340 auto mig_colpoints =
drift(
hit, pixdet, bfield, migrated_charges,
false);
341 LogDebug(
"Pixel3DDigitizerAlgorithm::drift") <<
"*****************"
343 <<
"****************";
361 energyOnCollector = energyOnCollector *
std::exp(-1.0 * kValue * drift_distance / max_radial_distance);
364 LogDebug(
"Pixel3DDigitizerAlgorithm::drift")
365 <<
"Drift distance = " << drift_distance * 1.0_um_inv <<
" [um], "
366 <<
"Initial electrons = " << super_charge.energy()
367 <<
" [electrons], Electrons after loss/diff= " << energyOnCollector <<
" [electrons] ";
371 current_pixel_int.first, current_pixel_int.second, 0.0, 0.0,
hit.tof(), energyOnCollector));
374 return collection_points;
382 const size_t hitIndex,
383 const uint32_t tofBin,
385 const std::vector<DigitizerUtility::SignalPoint>& collection_points) {
398 for (
const auto&
pt : collection_points) {
400 const int channel = pixelToChannel(
pt.position().x(),
pt.position().y());
410 LogDebug(
"Pixel3DDigitizerAlgorithm::induce_signal")
411 <<
" Induce charge at row,col:" <<
pt.position() <<
" N_electrons:" <<
pt.amplitude() <<
" [Channel:" <<
channel
412 <<
"]\n [Accumulated signal in this channel:" << the_signal[
channel].ampl() <<
"] "
413 <<
" Global index linked PSimHit:" << hitIndex;