16snd::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)
18 for (
auto snd_hit : snd_hits)
20 if (!snd_hit->isValid())
continue;
22 hit.
channel_index = 512 * snd_hit->GetMat() + 128 * snd_hit->GetSiPM() + snd_hit->GetSiPMChan();
23 int detectorID = snd_hit->GetDetectorID();
25 hit.
timestamp = snd_hit->GetTime(0) / ShipUnit::snd_TDC2ns;
28 hit.
timestamp = (scifi_geometry->
GetCorrectedTime(detectorID, snd_hit->GetTime(0)*ShipUnit::snd_TDC2ns, 0) / ShipUnit::snd_TDC2ns);
30 hit.
qdc = snd_hit->GetSignal(0);
31 hit.
is_x = snd_hit->isVertical();
62 if (configuration_.scifi_min_hits_in_window > configuration_.scifi_shower_window_width)
64 throw std::runtime_error{
"min_hits > window_width"};
67 if (configuration_.scifi_shower_window_width > configuration_.scifi_n_channels_per_plane)
69 throw std::runtime_error{
"window_width > n_channels_per_plane"};
73 is_hit.
x.resize(configuration_.scifi_n_channels_per_plane, 0);
74 is_hit.
y.resize(configuration_.scifi_n_channels_per_plane, 0);
76 for (
auto &hit : hits_)
78 if (hit.channel_index < 0 ||
79 hit.channel_index >= configuration_.scifi_n_channels_per_plane)
81 throw std::out_of_range{
"hit.channel_index out of range"};
83 (hit.is_x ? is_hit.
x : is_hit.
y)[hit.channel_index] = 1;
86 auto density = [&](
const std::vector<int> &hit_arr)
91 for (
int i{0}; i < configuration_.scifi_shower_window_width; ++i)
96 if (count >= configuration_.scifi_min_hits_in_window)
100 for (
int i = configuration_.scifi_shower_window_width; i < configuration_.scifi_n_channels_per_plane; ++i)
102 count += hit_arr[i] - hit_arr[i - configuration_.scifi_shower_window_width];
103 if (count >= configuration_.scifi_min_hits_in_window)
110 return density(is_hit.
x) && density(is_hit.
y);
115 std::vector<double> pos_x(configuration_.scifi_n_channels_per_plane, std::nan(
""));
116 std::vector<double> pos_y(configuration_.scifi_n_channels_per_plane, std::nan(
""));
118 for (
auto &hit : hits_)
124 pos_x[hit.channel_index] = hit.x;
128 pos_y[hit.channel_index] = hit.y;
133 auto largest_cluster = [&](
const std::vector<double> &positions)
135 int n =
static_cast<int>(positions.size());
137 int best_start = -1, best_end = -1, best_size = 0;
138 int start = -1, gap_count = 0, size = 0;
141 for (
int i = 0; i < n; ++i)
143 if (!std::isnan(positions[i]))
153 if (gap_count > max_gap)
155 if (size > best_size)
158 best_end = i - gap_count;
174 if (size > best_size)
182 if (best_start == -1 || best_end == -1)
187 for (
int i = best_start; i <= best_end; ++i)
189 if (!std::isnan(positions[i]))
196 return (count > 0) ? sum / count : std::nan(
"");
199 double cluster_x = largest_cluster(pos_x);
200 double cluster_y = largest_cluster(pos_y);
201 if (!(std::isnan(cluster_x) || std::isnan(cluster_y))) {
202 return ROOT::Math::XYZPoint(cluster_x, cluster_y, hits_[0].z);
204 return ROOT::Math::XYZPoint(std::nan(
""), std::nan(
""), std::nan(
""));
231 centroid_.SetXYZ(0, 0, 0);
232 double tot_qdc_x{0}, sum_qdc2_x{0.0};
233 double tot_qdc_y{0}, sum_qdc2_y{0.0};
234 std::vector<ScifiHit> cleaned_hits = hits_;
236 cleaned_hits.erase(std::remove_if(cleaned_hits.begin(), cleaned_hits.end(),
238 { return hit.qdc <= 0; }),
240 int counts_x = std::count_if(cleaned_hits.begin(), cleaned_hits.end(), [](
auto &hit)
241 { return hit.is_x; });
242 int counts_y =
static_cast<int>(cleaned_hits.size())-counts_x;
243 if (counts_x < configuration_.scifi_min_n_hits_for_centroid && counts_y < configuration_.scifi_min_n_hits_for_centroid ) {
244 centroid_ = ROOT::Math::XYZPoint(std::nan(
""), std::nan(
""), std::nan(
""));
248 for (
auto &hit : cleaned_hits)
254 centroid_.SetX(centroid_.X() + hit.x * hit.qdc);
255 tot_qdc_x += hit.qdc;
256 sum_qdc2_x += hit.qdc*hit.qdc;
260 centroid_.SetY(centroid_.Y() + hit.y * hit.qdc);
261 tot_qdc_y += hit.qdc;
262 sum_qdc2_y += hit.qdc*hit.qdc;
265 centroid_.SetZ(centroid_.Z() + hit.z * hit.qdc);
268 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(
""));
269 auto qdc_x_error_scaler = sqrt(sum_qdc2_x)/tot_qdc_x;
270 auto qdc_y_error_scaler = sqrt(sum_qdc2_y)/tot_qdc_y;
271 auto qdc_z_error_scaler = sqrt(sum_qdc2_x+sum_qdc2_y)/(tot_qdc_x+tot_qdc_y);
272 centroid_error_ = ROOT::Math::XYZPoint(configuration_.scifi_centroid_error_x*qdc_x_error_scaler,
273 configuration_.scifi_centroid_error_y*qdc_y_error_scaler,
274 configuration_.scifi_centroid_error_z*qdc_z_error_scaler);
280 qdc_sum.
x = std::accumulate(hits_.begin(), hits_.end(), 0.0, [&](
double current_sum,
auto &hit)
281 { return (hit.is_x && (hit.qdc > 0 || !only_positive)) ? (current_sum + hit.qdc) : current_sum; });
282 qdc_sum.y = std::accumulate(hits_.begin(), hits_.end(), 0.0, [&](
double current_sum,
auto &hit)
283 { return (!hit.is_x && (hit.qdc > 0 || !only_positive)) ? (current_sum + hit.qdc) : current_sum; });