15snd::analysis_tools::ScifiPlane::ScifiPlane(std::vector<sndScifiHit*> snd_hits,
const Configuration &configuration,
Scifi *scifi_geometry,
int station) : configuration_(configuration), centroid_(std::nan(
""), std::nan(
""), std::nan(
"")), centroid_error_(std::nan(
""), std::nan(
""), std::nan(
"")), station_(station)
17 for (
auto snd_hit : snd_hits)
19 if (!snd_hit->isValid())
continue;
21 hit.
channel_index = 512 * snd_hit->GetMat() + 128 * snd_hit->GetSiPM() + snd_hit->GetSiPMChan();
22 int detectorID = snd_hit->GetDetectorID();
24 hit.
timestamp = snd_hit->GetTime(0) / ShipUnit::snd_TDC2ns;
27 hit.
timestamp = (scifi_geometry->
GetCorrectedTime(detectorID, snd_hit->GetTime(0)*ShipUnit::snd_TDC2ns, 0) / ShipUnit::snd_TDC2ns);
29 hit.
qdc = snd_hit->GetSignal(0);
30 hit.
is_x = snd_hit->isVertical();
61 if (configuration_.scifi_min_hits_in_window > configuration_.scifi_shower_window_width)
63 throw std::runtime_error{
"min_hits > window_width"};
66 if (configuration_.scifi_shower_window_width > configuration_.scifi_n_channels_per_plane)
68 throw std::runtime_error{
"window_width > n_channels_per_plane"};
72 is_hit.
x.resize(configuration_.scifi_n_channels_per_plane, 0);
73 is_hit.
y.resize(configuration_.scifi_n_channels_per_plane, 0);
75 for (
auto &hit : hits_)
77 if (hit.channel_index < 0 ||
78 hit.channel_index >= configuration_.scifi_n_channels_per_plane)
80 throw std::out_of_range{
"hit.channel_index out of range"};
82 (hit.is_x ? is_hit.
x : is_hit.
y)[hit.channel_index] = 1;
85 auto density = [&](
const std::vector<int> &hit_arr)
90 for (
int i{0}; i < configuration_.scifi_shower_window_width; ++i)
95 if (count >= configuration_.scifi_min_hits_in_window)
99 for (
int i = configuration_.scifi_shower_window_width; i < configuration_.scifi_n_channels_per_plane; ++i)
101 count += hit_arr[i] - hit_arr[i - configuration_.scifi_shower_window_width];
102 if (count >= configuration_.scifi_min_hits_in_window)
109 return density(is_hit.
x) && density(is_hit.
y);
114 std::vector<double> pos_x(configuration_.scifi_n_channels_per_plane, std::nan(
""));
115 std::vector<double> pos_y(configuration_.scifi_n_channels_per_plane, std::nan(
""));
117 for (
auto &hit : hits_)
123 pos_x[hit.channel_index] = hit.x;
127 pos_y[hit.channel_index] = hit.y;
132 auto largest_cluster = [&](
const std::vector<double> &positions)
134 int n =
static_cast<int>(positions.size());
136 int best_start = -1, best_end = -1, best_size = 0;
137 int start = -1, gap_count = 0, size = 0;
140 for (
int i = 0; i < n; ++i)
142 if (!std::isnan(positions[i]))
152 if (gap_count > max_gap)
154 if (size > best_size)
157 best_end = i - gap_count;
173 if (size > best_size)
181 if (best_start == -1 || best_end == -1)
186 for (
int i = best_start; i <= best_end; ++i)
188 if (!std::isnan(positions[i]))
195 return (count > 0) ? sum / count : std::nan(
"");
198 double cluster_x = largest_cluster(pos_x);
199 double cluster_y = largest_cluster(pos_y);
200 if (!(std::isnan(cluster_x) || std::isnan(cluster_y))) {
201 return ROOT::Math::XYZPoint(cluster_x, cluster_y, hits_[0].z);
203 return ROOT::Math::XYZPoint(std::nan(
""), std::nan(
""), std::nan(
""));
230 centroid_.SetXYZ(0, 0, 0);
231 double tot_qdc_x{0}, sum_qdc2_x{0.0};
232 double tot_qdc_y{0}, sum_qdc2_y{0.0};
233 std::vector<ScifiHit> cleaned_hits = hits_;
235 cleaned_hits.erase(std::remove_if(cleaned_hits.begin(), cleaned_hits.end(),
237 { return hit.qdc <= 0; }),
239 int counts_x = std::count_if(cleaned_hits.begin(), cleaned_hits.end(), [](
auto &hit)
240 { return hit.is_x; });
241 int counts_y =
static_cast<int>(cleaned_hits.size())-counts_x;
242 if (counts_x < configuration_.scifi_min_n_hits_for_centroid && counts_y < configuration_.scifi_min_n_hits_for_centroid ) {
243 centroid_ = ROOT::Math::XYZPoint(std::nan(
""), std::nan(
""), std::nan(
""));
247 for (
auto &hit : cleaned_hits)
253 centroid_.SetX(centroid_.X() + hit.x * hit.qdc);
254 tot_qdc_x += hit.qdc;
255 sum_qdc2_x += hit.qdc*hit.qdc;
259 centroid_.SetY(centroid_.Y() + hit.y * hit.qdc);
260 tot_qdc_y += hit.qdc;
261 sum_qdc2_y += hit.qdc*hit.qdc;
264 centroid_.SetZ(centroid_.Z() + hit.z * hit.qdc);
267 centroid_ = ROOT::Math::XYZPoint((tot_qdc_x > 0) ? centroid_.X() / tot_qdc_x : std::nan(
""), (tot_qdc_y > 0) ? centroid_.Y() / tot_qdc_y : std::nan(
""), (tot_qdc_x+tot_qdc_y > 0) ? centroid_.Z() / (tot_qdc_x+tot_qdc_y) : std::nan(
""));
268 auto qdc_x_error_scaler = sqrt(sum_qdc2_x)/tot_qdc_x;
269 auto qdc_y_error_scaler = sqrt(sum_qdc2_y)/tot_qdc_y;
270 auto qdc_z_error_scaler = sqrt(sum_qdc2_x+sum_qdc2_y)/(tot_qdc_x+tot_qdc_y);
271 centroid_error_ = ROOT::Math::XYZPoint(configuration_.scifi_centroid_error_x*qdc_x_error_scaler,
272 configuration_.scifi_centroid_error_y*qdc_y_error_scaler,
273 configuration_.scifi_centroid_error_z*qdc_z_error_scaler);
279 qdc_sum.
x = std::accumulate(hits_.begin(), hits_.end(), 0.0, [&](
double current_sum,
auto &hit)
280 { return (hit.is_x && (hit.qdc > 0 || !only_positive)) ? (current_sum + hit.qdc) : current_sum; });
281 qdc_sum.y = std::accumulate(hits_.begin(), hits_.end(), 0.0, [&](
double current_sum,
auto &hit)
282 { return (!hit.is_x && (hit.qdc > 0 || !only_positive)) ? (current_sum + hit.qdc) : current_sum; });