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 _np_column_radius(5.0_um),
58 _ohm_column_radius(5.0_um) {
63 <<
"Algorithm constructed \n"
64 <<
"Configuration parameters:\n"
76 std::vector<PSimHit>::const_iterator inputEnd,
77 const size_t inputBeginGlobalIndex,
78 const unsigned int tofBin,
85 size_t simHitGlobalIndex = inputBeginGlobalIndex;
88 for (
auto it = inputBegin; it != inputEnd; ++it, ++simHitGlobalIndex) {
90 if (it->detUnitId() != detId) {
94 LogDebug(
"Pixel3DDigitizerAlgorithm:: Geant4 hit info: ")
95 << (*it).particleType() <<
" " << (*it).pabs() <<
" " << (*it).energyLoss() <<
" " << (*it).tof() <<
" "
96 << (*it).trackId() <<
" " << (*it).processType() <<
" " << (*it).detUnitId() << (*it).entryPoint() <<
" "
101 const auto global_hit_position = pix3Ddet->
surface().
toGlobal(it->localPosition()).
mag();
108 std::vector<DigitizerUtility::EnergyDepositUnit> ionization_points;
113 const auto collection_points =
drift(*it, pix3Ddet, bfield, ionization_points,
true);
117 induce_signal(*it, simHitGlobalIndex, tofBin, pix3Ddet, collection_points);
127 const std::pair<float, float>& half_pitch)
const {
146 const float& ncarriers,
148 const std::pair<float, float> hpitches,
154 const float _max_migration_radius = 0.4_um;
161 if (
std::abs(
pos.x() - hpitches.first) < _max_migration_radius) {
163 pitch = hpitches.first;
164 }
else if (
std::abs(
pos.y() - hpitches.second) < _max_migration_radius) {
166 pitch = hpitches.second;
169 return std::vector<DigitizerUtility::EnergyDepositUnit>();
174 std::vector<DigitizerUtility::EnergyDepositUnit> migrated_charge;
177 const float _diffusion_step = 0.1_um;
180 std::vector<float> pos_moving({
pos.x(),
pos.y(),
pos.z()});
182 std::function<std::vector<float>(
int)> do_step =
183 [&pos_moving, &u_drift, _diffusion_step](
int i) -> std::vector<float> {
184 auto dd = u_drift(pos_moving[0], pos_moving[1]);
185 return std::vector<float>(
186 {
i * _diffusion_step *
dd.x(),
i * _diffusion_step *
dd.y(),
i * _diffusion_step *
dd.z()});
189 LogDebug(
"Pixel3DDigitizerAlgorithm::diffusion")
190 <<
"\nMax. radius from the pixel edge to migrate charge: " << _max_migration_radius * 1.0_um_inv <<
" [um]"
191 <<
"\nMigration axis: " << displ_ind
192 <<
"\n(super-)Charge distance to the pixel edge: " << (
pitch - pos_moving[displ_ind]) * 1.0_um_inv <<
" [um]";
195 const float _distance0 = 300.0_um;
196 const float _sigma0 = 3.4_um;
198 const float _TOL = 1
e-6;
200 const float _N_SIGMA = 3.0;
206 float current_carriers = ncarriers;
207 std::vector<float> newpos({pos_moving[0], pos_moving[1], pos_moving[2]});
208 float distance_edge = 0.0_um;
210 std::transform(pos_moving.begin(), pos_moving.end(), do_step(
i).begin(), pos_moving.begin(), std::plus<float>());
213 double sigma =
std::sqrt(
i * _diffusion_step / _distance0) * (_distance0 /
thickness) * _sigma0;
216 float migrated_e = current_carriers * (1.0 - std::erf(distance_edge / sigma));
218 LogDebug(
"(super-)charge diffusion") <<
"step-" <<
i <<
", Initial Ne= " << ncarriers <<
", "
219 <<
"r=(" << pos_moving[0] * 1.0_um_inv <<
", " << pos_moving[1] * 1.0_um_inv
220 <<
", " << pos_moving[2] * 1.0_um_inv <<
") [um], "
221 <<
"Migrated charge: " << migrated_e;
226 if ((migrated_e - _TOL) < 1.0) {
230 current_carriers -= migrated_e;
235 std::vector<float> newpos(pos_moving);
237 newpos[displ_ind] += std::copysign(_N_SIGMA * sigma, newpos[displ_ind]);
242 }
while (
std::abs(distance_edge) < _max_migration_radius);
244 return migrated_charge;
258 const std::vector<DigitizerUtility::EnergyDepositUnit>& ionization_points,
259 bool diffusion_activated) {
269 const auto half_pitch = std::make_pair<float, float>(
pitch.first * 0.5,
pitch.second * 0.5);
273 const float max_radial_distance =
274 std::sqrt(half_pitch.first * half_pitch.first + half_pitch.second * half_pitch.second);
283 LogDebug(
"Pixel3DDigitizerAlgorithm::drift")
284 <<
"Pixel pitch:" <<
pitch.first * 1.0_um_inv <<
", " <<
pitch.second * 1.0_um_inv <<
" [um]";
289 const float theta = std::atan2(
y,
x);
293 std::vector<DigitizerUtility::SignalPoint> collection_points;
295 collection_points.reserve(ionization_points.size());
299 const float _RAD_DAMAGE = 0.001;
301 for (
const auto& super_charge : ionization_points) {
304 const auto current_pixel_int = std::make_pair(std::floor(current_pixel.first), std::floor(current_pixel.second));
308 const auto relative_position_at_pc =
309 std::make_pair((current_pixel.first - current_pixel_int.first) *
pitch.first,
310 (current_pixel.second - current_pixel_int.second) *
pitch.second);
313 LocalPoint position_at_pc(relative_position_at_pc.first - center_proxy_cell.
x(),
314 relative_position_at_pc.second - center_proxy_cell.
y(),
317 LogDebug(
"Pixel3DDigitizerAlgorithm::drift")
318 <<
"(super-)Charge\nlocal position: (" << super_charge.x() * 1.0_um_inv <<
", " << super_charge.y() * 1.0_um_inv
319 <<
", " << super_charge.z() * 1.0_um_inv <<
") [um]"
320 <<
"\nMeasurement Point (row,column) (" << current_pixel.first <<
", " << current_pixel.second <<
")"
321 <<
"\nProxy pixel-cell frame (centered at left-down corner): (" << relative_position_at_pc.first * 1.0_um_inv
322 <<
", " << relative_position_at_pc.second * 1.0_um_inv <<
") [um]"
323 <<
"\nProxy pixel-cell frame (centered at n-column): (" << position_at_pc.x() * 1.0_um_inv <<
", "
324 << position_at_pc.y() * 1.0_um_inv <<
") [um] "
325 <<
"\nNe=" << super_charge.energy() <<
" electrons";
329 LogDebug(
"Pixel3DDigitizerAlgorithm::drift") <<
"Remove charge, inside the n-column or p-column!!";
335 if (diffusion_activated) {
336 auto migrated_charges =
diffusion(position_at_pc, super_charge.energy(), drift_direction, half_pitch,
thickness);
338 for (
auto&
mc : migrated_charges) {
343 const float pixel_x = current_pixel_int.first + (
mc.x() + center_proxy_cell.
x()) /
pitch.first;
344 const float pixel_y = current_pixel_int.second + (
mc.y() + center_proxy_cell.
y()) /
pitch.second;
348 if (!migrated_charges.empty()) {
349 LogDebug(
"Pixel3DDigitizerAlgorithm::drift") <<
"****************"
350 <<
"MIGRATING (super-)charges"
351 <<
"****************";
353 auto mig_colpoints =
drift(
hit, pixdet, bfield, migrated_charges,
false);
354 LogDebug(
"Pixel3DDigitizerAlgorithm::drift") <<
"*****************"
356 <<
"****************";
374 energyOnCollector = energyOnCollector *
std::exp(-1.0 * kValue * drift_distance / max_radial_distance);
377 LogDebug(
"Pixel3DDigitizerAlgorithm::drift")
378 <<
"Drift distance = " << drift_distance * 1.0_um_inv <<
" [um], "
379 <<
"Initial electrons = " << super_charge.energy()
380 <<
" [electrons], Electrons after loss/diff= " << energyOnCollector <<
" [electrons] ";
384 current_pixel_int.first, current_pixel_int.second, 0.0, 0.0,
hit.tof(), energyOnCollector));
387 return collection_points;
395 const size_t hitIndex,
396 const unsigned int tofBin,
398 const std::vector<DigitizerUtility::SignalPoint>& collection_points) {
407 for (
const auto&
pt : collection_points) {
418 LogDebug(
"Pixel3DDigitizerAlgorithm::induce_signal")
419 <<
" Induce charge at row,col:" << rowcol <<
" N_electrons:" <<
pt.amplitude() <<
" [Channel:" <<
channel
420 <<
"]\n [Accumulated signal in this channel:" << the_signal[
channel].ampl() <<
"]";