303 point->Momentum(mom);
306 Double_t mnoc = 1.0, mass = 3.7283999;
322 cout <<
"particle, pdg_code = " << part->
PdgCode() <<
"\n";
323 cout <<
" px:py:pz = ( " << px <<
" : " << py <<
" : " << pz <<
" )\n";
324 cout <<
" mass = " << mass <<
"\n";
325 cout <<
" beta = " <<
beta <<
"\n";
326 cout <<
" gamma = " << gamma <<
"\n";
327 cout <<
" charge = " << charge <<
"\n";
328 cout <<
" mnoc = " << mnoc <<
"\n";
344 if (z_distance_from_in_to_out <= 0.0) {
345 LOG(warn) <<
"BmnGemStripModule::AddRealPointFull(): Point (" << x <<
" : " << y <<
" : " << z
346 <<
") has a track with an incorrect length";
351 Double_t vector_coeff =
fabs(z_distance_from_in_to_out / pz);
354 Double_t x_vec_from_in_to_out = vector_coeff * px;
355 Double_t y_vec_from_in_to_out = vector_coeff * py;
356 Double_t z_vec_from_in_to_out = vector_coeff * pz;
359 Double_t x_out = x + x_vec_from_in_to_out;
360 Double_t y_out = y + y_vec_from_in_to_out;
365 if (x_out < XMinModule || x_out >
XMaxModule) {
371 x_vec_from_in_to_out = x_out - x;
372 vector_coeff = x_vec_from_in_to_out / px;
374 y_vec_from_in_to_out = vector_coeff * py;
375 z_vec_from_in_to_out = vector_coeff * pz;
377 y_out = y + y_vec_from_in_to_out;
381 if (y_out < YMinModule || y_out >
YMaxModule) {
387 y_vec_from_in_to_out = y_out - y;
388 vector_coeff = y_vec_from_in_to_out / py;
390 x_vec_from_in_to_out = vector_coeff * px;
391 z_vec_from_in_to_out = vector_coeff * pz;
393 x_out = x + x_vec_from_in_to_out;
400 std::sqrt((x_vec_from_in_to_out) * (x_vec_from_in_to_out) + (y_vec_from_in_to_out) * (y_vec_from_in_to_out)
401 + (z_vec_from_in_to_out) * (z_vec_from_in_to_out));
404 Double_t current_length_ratio = 0.0;
410 std::vector<CollPoint> collision_points;
412 while (current_length < track_length) {
419 current_length += current_step;
421 if (current_length > track_length)
424 current_length_ratio = current_length / track_length;
426 Double_t current_x = x + current_length_ratio * x_vec_from_in_to_out;
427 Double_t current_y = y + current_length_ratio * y_vec_from_in_to_out;
428 Double_t current_z = z + current_length_ratio * z_vec_from_in_to_out;
430 collision_points.push_back(
CollPoint(current_x, current_y, current_z));
467 vector<StripCluster> cluster_layers(n_strip_layers,
StripCluster());
472 for (
size_t icoll = 0; icoll < collision_points.size(); ++icoll) {
474 Double_t xcoll = collision_points[icoll].x;
475 Double_t ycoll = collision_points[icoll].y;
476 Double_t zcoll = collision_points[icoll].z;
489 xmean = p0_xmean + p1_xmean * zdist + p2_xmean * zdist * zdist + p3_xmean * zdist * zdist * zdist;
490 sigma = p0_sigma + p1_sigma * zdist + p2_sigma * zdist * zdist + p3_sigma * zdist * zdist * zdist
491 + p4_sigma * zdist * zdist * zdist * zdist + p5_sigma * zdist * zdist * zdist * zdist * zdist;
494 Int_t n_electrons_cluster =
gRandom->Landau(1.027, 0.11);
495 if (n_electrons_cluster < 1)
496 n_electrons_cluster = 1;
497 if (n_electrons_cluster > 6)
498 n_electrons_cluster = 6;
500 for (
Int_t ielectron = 0; ielectron < n_electrons_cluster; ++ielectron) {
518 if (zdist < level1) {
521 if (zdist >= level1 && zdist < level2) {
522 total_gain = gain_gem3;
524 if (zdist >= level2 && zdist < level3) {
525 total_gain = gain_gem3 * gain_gem2;
527 if (zdist >= level3) {
528 total_gain = gain_gem3 * gain_gem2 * gain_gem1;
532 double x_readout, y_readout;
534 for (
int igain = 0; igain < total_gain; ++igain) {
538 x_readout =
gRandom->Gaus(xcoll + xmean, sigma);
540 x_readout =
gRandom->Gaus(xcoll - xmean, sigma);
543 y_readout =
gRandom->Gaus(ycoll, sigma);
545 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
547 if (!
StripLayers[ilayer].IsPointInsideStripLayer(x_readout, y_readout))
550 Double_t strip_pos =
StripLayers[ilayer].ConvertPointToStripPosition(x_readout, y_readout);
552 Double_t dstrip = strip_pos - (int)strip_pos;
556 if (dstrip >= 0.4 && dstrip < 0.6)
561 if (dstrip >= 0.3 && dstrip < 0.7)
569 cluster_layers[ilayer].AddStrip((
Int_t)strip_pos, 1.0);
584 vector<Double_t> cluster_mean_position(n_strip_layers, 0.0);
585 vector<Double_t> cluster_total_signal(n_strip_layers, 0.0);
587 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
589 if (cluster_layers[ilayer].GetClusterSize() > 0) {
590 for (
int i = 0;
i < cluster_layers[ilayer].GetClusterSize(); ++
i) {
591 cluster_mean_position[ilayer] += (cluster_layers[ilayer].Strips[
i] + 0.5)
592 * cluster_layers[ilayer].Signals[
i];
593 cluster_total_signal[ilayer] += cluster_layers[ilayer].Signals[
i];
595 cluster_mean_position[ilayer] /= cluster_total_signal[ilayer];
598 cluster_layers[ilayer].MeanPosition = cluster_mean_position[ilayer];
599 cluster_layers[ilayer].TotalSignal = cluster_total_signal[ilayer];
604 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
605 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x, y);
608 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
609 cluster_layers[ilayer].OriginPosition =
610 StripLayers[ilayer].ConvertPointToStripPosition(x_out, y_out);
615 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
616 cluster_layers[ilayer].OriginPosition =
617 StripLayers[ilayer].ConvertPointToStripPosition(x_out, y_out);
620 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
621 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x, y);
626 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
627 cluster_layers[ilayer].PositionResidual =
628 cluster_layers[ilayer].MeanPosition - cluster_layers[ilayer].OriginPosition;
645 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
646 for (
size_t ielement = 0; ielement < cluster_layers[ilayer].Strips.size(); ++ielement) {
647 Int_t strip_num = cluster_layers[ilayer].Strips.at(ielement);
648 Double_t strip_signal = cluster_layers[ilayer].Signals.at(ielement);
649 StripLayers[ilayer].AddStripSignal(strip_num, strip_signal);
655 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
656 for (
size_t ielement = 0; ielement < cluster_layers[ilayer].Strips.size(); ++ielement) {
657 Int_t strip_num = cluster_layers[ilayer].Strips.at(ielement);
658 Double_t strip_signal = cluster_layers[ilayer].Signals.at(ielement);
659 StripLayers[ilayer].AddLinkToStripMatch(strip_num, strip_signal / cluster_layers[ilayer].TotalSignal,
673 LOG(warn) <<
"BmnGemStripModule::AddRealPointFull(): Point (" << x <<
" : " << y <<
" : " << z
674 <<
") is out of the readout plane or inside a dead zone";
698 const Int_t n_track_segments = 64;
699 const Int_t n_segs_features = 16;
700 const Int_t n_ann_inputs = 5 + n_segs_features;
701 const Int_t nx_bins = 80, ny_bins = 80;
702 const Double_t dx_area = 1.25, dy_area = 1.25;
712 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): Point (" << x <<
" : " << y <<
" : " << z
713 <<
") is out of the readout plane or inside a dead zone";
720 Double_t mnoc = 1.0, mass = 3.7283999;
747 if (z_distance_from_in_to_out <= 0.0) {
748 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): Point (" << x <<
" : " << y <<
" : " << z
749 <<
") has a track with an incorrect length";
754 Double_t vector_coeff =
fabs(z_distance_from_in_to_out / pz);
757 Double_t x_vec_from_in_to_out = vector_coeff * px;
758 Double_t y_vec_from_in_to_out = vector_coeff * py;
759 Double_t z_vec_from_in_to_out = vector_coeff * pz;
762 Double_t x_out = x + x_vec_from_in_to_out;
763 Double_t y_out = y + y_vec_from_in_to_out;
764 Double_t z_out = z + z_vec_from_in_to_out;
768 if (x_out < XMinModule || x_out >
XMaxModule) {
774 x_vec_from_in_to_out = x_out - x;
775 vector_coeff = x_vec_from_in_to_out / px;
777 y_vec_from_in_to_out = vector_coeff * py;
778 z_vec_from_in_to_out = vector_coeff * pz;
780 y_out = y + y_vec_from_in_to_out;
781 z_out = z + z_vec_from_in_to_out;
784 if (y_out < YMinModule || y_out >
YMaxModule) {
790 y_vec_from_in_to_out = y_out - y;
791 vector_coeff = y_vec_from_in_to_out / py;
793 x_vec_from_in_to_out = vector_coeff * px;
794 z_vec_from_in_to_out = vector_coeff * pz;
796 x_out = x + x_vec_from_in_to_out;
797 z_out = z + z_vec_from_in_to_out;
803 std::sqrt((x_vec_from_in_to_out) * (x_vec_from_in_to_out) + (y_vec_from_in_to_out) * (y_vec_from_in_to_out)
804 + (z_vec_from_in_to_out) * (z_vec_from_in_to_out));
807 Double_t current_length_ratio = 0.0;
809 Int_t collisions_cnt = 0;
813 std::vector<CollPoint> collision_points;
815 while (current_length < track_length) {
822 current_length += current_step;
824 if (current_length > track_length)
827 current_length_ratio = current_length / track_length;
829 Double_t current_x = x + current_length_ratio * x_vec_from_in_to_out;
830 Double_t current_y = y + current_length_ratio * y_vec_from_in_to_out;
831 Double_t current_z = z + current_length_ratio * z_vec_from_in_to_out;
833 collision_points.push_back(
CollPoint(current_x, current_y, current_z));
868 std::shared_ptr<const BmnGemStripFdeepModel> ann_holder;
871 ann_model = ann_holder.get();
873 static std::mutex checked_mutex;
875 std::pair<std::shared_ptr<const BmnGemStripFdeepModel>, std::string>>
878 std::lock_guard<std::mutex> lock(checked_mutex);
880 LOG(warn) <<
"BmnGemStripModule::" << __func__
881 <<
"(): fdeep model is not available, the standard method is used";
883 auto it = checked.find(ann_model);
884 if (it == checked.end()) {
885 const Int_t expected_out = nx_bins * ny_bins;
888 why =
"input " + std::to_string(ann_model->
GetInputDim()) +
", expected "
889 + std::to_string(n_ann_inputs) +
"; output " + std::to_string(ann_model->
GetOutputDim())
890 +
", expected " + std::to_string(expected_out);
892 LOG(info) <<
"BmnGemStripModule::" << __func__ <<
"(): fdeep model " << ann_model->
GetFilePath()
894 it = checked.emplace(ann_model, std::make_pair(ann_holder, why)).first;
896 if (!it->second.second.empty()) {
897 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): the model " << ann_model->
GetFilePath()
898 <<
" is not suitable (" << it->second.second <<
"), the standard method is used";
906 const Bool_t useANN = (theta_deg_abs < maxThetaAngle) && !onlyStandard && ann_model;
910 vector<StripCluster> cluster_layers(n_strip_layers,
StripCluster());
914 for (
size_t icoll = 0; icoll < collision_points.size(); ++icoll) {
916 Double_t xcoll = collision_points[icoll].x;
917 Double_t ycoll = collision_points[icoll].y;
918 Double_t zcoll = collision_points[icoll].z;
931 xmean = p0_xmean + p1_xmean * zdist + p2_xmean * zdist * zdist + p3_xmean * zdist * zdist * zdist;
932 sigma = p0_sigma + p1_sigma * zdist + p2_sigma * zdist * zdist + p3_sigma * zdist * zdist * zdist
933 + p4_sigma * zdist * zdist * zdist * zdist + p5_sigma * zdist * zdist * zdist * zdist * zdist;
936 Int_t n_electrons_cluster =
gRandom->Landau(1.027, 0.11);
937 if (n_electrons_cluster < 1)
938 n_electrons_cluster = 1;
939 if (n_electrons_cluster > 6)
940 n_electrons_cluster = 6;
946 std::sqrt((xcoll - x) * (xcoll - x) + (ycoll - y) * (ycoll - y) + (zcoll - z) * (zcoll - z));
948 dist_from_start = std::sqrt((xcoll - x_out) * (xcoll - x_out) + (ycoll - y_out) * (ycoll - y_out)
949 + (zcoll - z_out) * (zcoll - z_out));
951 Int_t segment = (
Int_t)(dist_from_start / track_length * n_track_segments);
952 if (segment >= n_track_segments)
953 segment = n_track_segments - 1;
956 for (
Int_t ielectron = 0; ielectron < n_electrons_cluster; ++ielectron) {
972 if (zdist < level1) {
975 if (zdist >= level1 && zdist < level2) {
976 total_gain = gain_gem3;
978 if (zdist >= level2 && zdist < level3) {
979 total_gain = gain_gem3 * gain_gem2;
981 if (zdist >= level3) {
982 total_gain = gain_gem3 * gain_gem2 * gain_gem1;
993 double x_readout, y_readout;
995 for (
int igain = 0; igain < total_gain; ++igain) {
999 x_readout =
gRandom->Gaus(xcoll + xmean, sigma);
1001 x_readout =
gRandom->Gaus(xcoll - xmean, sigma);
1004 y_readout =
gRandom->Gaus(ycoll, sigma);
1006 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1008 if (!
StripLayers[ilayer].IsPointInsideStripLayer(x_readout, y_readout))
1011 Double_t strip_pos =
StripLayers[ilayer].ConvertPointToStripPosition(x_readout, y_readout);
1013 Double_t dstrip = strip_pos - (int)strip_pos;
1016 if (dstrip >= 0.4 && dstrip < 0.6)
1020 if (dstrip >= 0.3 && dstrip < 0.7)
1025 cluster_layers[ilayer].AddStrip((
Int_t)strip_pos, 1.0);
1055 drift_direction = 1;
1058 if (!segs.empty()) {
1063 LOG(error) <<
"BmnGemStripModule::" << __func__
1072 vector<Float_t> segs_norm(n_segs_features, 0.0f);
1073 if (max_segment_val > 0.0) {
1074 for (
Int_t iseg = 0; iseg < n_segs_features; ++iseg)
1092 std::vector<float> input_data;
1093 input_data.reserve(n_ann_inputs);
1094 input_data.push_back(
static_cast<float>(px_norm));
1095 input_data.push_back(
static_cast<float>(py_norm));
1096 input_data.push_back(
static_cast<float>(pz_norm));
1097 input_data.push_back(
static_cast<float>(drift_direction));
1098 input_data.push_back(
static_cast<float>(bfield));
1099 input_data.insert(input_data.end(), segs_norm.begin(), segs_norm.end());
1101 if (total_charge > 0.0) {
1103 const auto img = ann_model->
Predict(input_data);
1104 if (img.size() !=
static_cast<std::size_t
>(nx_bins * ny_bins)) {
1105 LOG(error) <<
"BmnGemStripModule::" << __func__ <<
"(): model output size = " << img.size()
1106 <<
", expected " << nx_bins * ny_bins;
1108 Double_t x_bin_size = 2 * dx_area / nx_bins;
1109 Double_t y_bin_size = 2 * dy_area / ny_bins;
1110 Double_t x_min_area = x_mc - dx_area;
1111 Double_t y_min_area = y_mc - dy_area;
1114 std::vector<Double_t> norm_content(nx_bins * ny_bins, 0.0);
1116 for (
Int_t idx = 0; idx < nx_bins * ny_bins; ++idx) {
1117 norm_content[idx] = (img.at(idx) - (-1.0)) / (1.0 - (-1.0));
1118 sum_norm += norm_content[idx];
1122 const Double_t ann_correction = 0.8;
1125 signal_scale = (total_charge / sum_norm) * ann_correction;
1127 Double_t threshold = 0.0001 * total_charge;
1131 for (
Int_t iy = ny_bins - 1; iy >= 0; --iy) {
1132 for (
Int_t ix = 0; ix < nx_bins; ++ix, ++idx) {
1133 Double_t content = norm_content[idx] * signal_scale;
1134 if (content <= threshold)
1137 Double_t x_bin_coord = ix * x_bin_size + x_bin_size * 0.5 + x_min_area;
1138 Double_t y_bin_coord = iy * y_bin_size + y_bin_size * 0.5 + y_min_area;
1140 Int_t n_rand_points = 10;
1141 Double_t distr_content = content / n_rand_points;
1142 for (
Int_t irp = 0; irp < n_rand_points; ++irp) {
1144 gRandom->Uniform(x_bin_coord - x_bin_size * 0.5, x_bin_coord + x_bin_size * 0.5);
1146 gRandom->Uniform(y_bin_coord - y_bin_size * 0.5, y_bin_coord + y_bin_size * 0.5);
1148 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1149 if (!
StripLayers[ilayer].IsPointInsideStripLayer(x_distr, y_distr))
1152 cluster_layers[ilayer].AddStrip((
Int_t)strip_pos, distr_content);
1167 vector<Double_t> cluster_mean_position(n_strip_layers, 0.0);
1168 vector<Double_t> cluster_total_signal(n_strip_layers, 0.0);
1170 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1172 if (cluster_layers[ilayer].GetClusterSize() > 0) {
1174 for (
int i = 0;
i < cluster_layers[ilayer].GetClusterSize(); ++
i) {
1175 cluster_mean_position[ilayer] += (cluster_layers[ilayer].Strips[
i] + 0.5)
1176 * cluster_layers[ilayer].Signals[
i];
1177 cluster_total_signal[ilayer] += cluster_layers[ilayer].Signals[
i];
1179 cluster_mean_position[ilayer] /= cluster_total_signal[ilayer];
1182 cluster_layers[ilayer].MeanPosition = cluster_mean_position[ilayer];
1183 cluster_layers[ilayer].TotalSignal = cluster_total_signal[ilayer];
1188 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1189 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x, y);
1192 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1193 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x_out, y_out);
1198 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1199 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x_out, y_out);
1202 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1203 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x, y);
1208 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1209 cluster_layers[ilayer].PositionResidual =
1210 cluster_layers[ilayer].MeanPosition - cluster_layers[ilayer].OriginPosition;
1211 cluster_layers[ilayer].SetType(
StripLayers[ilayer].GetType());
1217 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1222 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1228 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1229 for (
size_t ielement = 0; ielement < cluster_layers[ilayer].Strips.size(); ++ielement) {
1230 Int_t strip_num = cluster_layers[ilayer].Strips.at(ielement);
1231 Double_t strip_signal = cluster_layers[ilayer].Signals.at(ielement);
1232 StripLayers[ilayer].AddStripSignal(strip_num, strip_signal);
1238 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1239 for (
size_t ielement = 0; ielement < cluster_layers[ilayer].Strips.size(); ++ielement) {
1240 Int_t strip_num = cluster_layers[ilayer].Strips.at(ielement);
1241 Double_t strip_signal = cluster_layers[ilayer].Signals.at(ielement);
1242 StripLayers[ilayer].AddLinkToStripMatch(strip_num, strip_signal / cluster_layers[ilayer].TotalSignal,
1274 const Bool_t kParallelANNLayers =
false;
1278 const Int_t n_track_segments = 64;
1279 const Int_t n_segs_features = n_track_segments;
1280 const Int_t n_ann_inputs = 5 + n_segs_features + 3;
1281 Int_t n_ann_strips = 0;
1287 std::shared_ptr<const BmnGemStripFdeepModel> ann_holder;
1289 if (!onlyStandard) {
1291 ann_model = ann_holder.get();
1293 static std::mutex checked_mutex;
1295 std::pair<std::shared_ptr<const BmnGemStripFdeepModel>, std::string>>
1298 std::lock_guard<std::mutex> lock(checked_mutex);
1300 LOG(warn) <<
"BmnGemStripModule::" << __func__
1301 <<
"(): fdeep model is not available, the standard method is used";
1303 auto it = checked.find(ann_model);
1304 if (it == checked.end()) {
1307 why =
"input " + std::to_string(ann_model->
GetInputDim()) +
", expected "
1308 + std::to_string(n_ann_inputs);
1312 LOG(info) <<
"BmnGemStripModule::" << __func__ <<
"(): fdeep model " << ann_model->
GetFilePath()
1313 <<
" is used (ANN for |theta| < " << maxThetaAngle <<
" deg, window "
1315 it = checked.emplace(ann_model, std::make_pair(ann_holder, why)).first;
1317 if (!it->second.second.empty()) {
1318 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): the model " << ann_model->
GetFilePath()
1319 <<
" is not suitable (" << it->second.second <<
"), the standard method is used";
1320 ann_model =
nullptr;
1330 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): Point (" << x <<
" : " << y <<
" : " << z
1331 <<
") is out of the readout plane or inside a dead zone";
1336 Int_t pdg = pdg_code;
1344 if (points && mctracks && refID >= 0 && refID < points->GetEntriesFast()) {
1346 if (point && point->GetTrackID() >= 0 && point->GetTrackID() < mctracks->
GetEntriesFast())
1353 static std::atomic<bool> no_mc_reported{
false};
1354 if (!no_mc_reported.exchange(
true))
1355 LOG(warn) <<
"BmnGemStripModule::" << __func__
1356 <<
"(): pdg_code = 0 and the MC track is not available (no GemDigitizer or MC point), "
1357 "the He4 mass is used (this warning is printed once)";
1364 Double_t mnoc = 1.0, mass = 3.7283999;
1366 mass = part->
Mass();
1367 if (mass > 0.0001) {
1382 Double_t z_distance_from_in_to_out;
1392 if (z_distance_from_in_to_out <= 0.0) {
1393 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): Point (" << x <<
" : " << y <<
" : " << z
1394 <<
") has a track with an incorrect length";
1399 Double_t vector_coeff =
fabs(z_distance_from_in_to_out / pz);
1402 Double_t x_vec_from_in_to_out = vector_coeff * px;
1403 Double_t y_vec_from_in_to_out = vector_coeff * py;
1404 Double_t z_vec_from_in_to_out = vector_coeff * pz;
1407 Double_t x_out = x + x_vec_from_in_to_out;
1408 Double_t y_out = y + y_vec_from_in_to_out;
1409 Double_t z_out = z + z_vec_from_in_to_out;
1413 if (x_out < XMinModule || x_out >
XMaxModule) {
1419 x_vec_from_in_to_out = x_out - x;
1420 vector_coeff = x_vec_from_in_to_out / px;
1422 y_vec_from_in_to_out = vector_coeff * py;
1423 z_vec_from_in_to_out = vector_coeff * pz;
1425 y_out = y + y_vec_from_in_to_out;
1426 z_out = z + z_vec_from_in_to_out;
1429 if (y_out < YMinModule || y_out >
YMaxModule) {
1435 y_vec_from_in_to_out = y_out - y;
1436 vector_coeff = y_vec_from_in_to_out / py;
1438 x_vec_from_in_to_out = vector_coeff * px;
1439 z_vec_from_in_to_out = vector_coeff * pz;
1441 x_out = x + x_vec_from_in_to_out;
1442 z_out = z + z_vec_from_in_to_out;
1453 std::sqrt((x_vec_from_in_to_out) * (x_vec_from_in_to_out) + (y_vec_from_in_to_out) * (y_vec_from_in_to_out)
1454 + (z_vec_from_in_to_out) * (z_vec_from_in_to_out));
1460 const Bool_t useANN = (theta_deg_abs < maxThetaAngle) && ann_model;
1463 const Bool_t use_external_segs = useANN && !segs.empty();
1464 if (use_external_segs && segs.size() <
static_cast<size_t>(n_segs_features)) {
1465 LOG(error) <<
"BmnGemStripModule::" << __func__ <<
"(): segment vector size = " << segs.size()
1466 <<
", the model requires " << n_segs_features;
1497 vector<StripCluster> cluster_layers(n_strip_layers,
StripCluster());
1500 vector<Int_t> seg_local(n_track_segments, 0);
1506 vector<vector<Double_t>> strip_acc;
1507 vector<Int_t> acc_min, acc_max;
1508 vector<char> layer_vertical;
1510 strip_acc.resize(n_strip_layers);
1511 acc_min.assign(n_strip_layers, std::numeric_limits<Int_t>::max());
1512 acc_max.assign(n_strip_layers, -1);
1513 layer_vertical.assign(n_strip_layers, 0);
1514 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1515 strip_acc[ilayer].assign(std::max(0,
StripLayers[ilayer].GetNStrips()), 0.0);
1521 if (!use_external_segs) {
1524 Double_t current_length_ratio = 0.0;
1528 std::vector<CollPoint> collision_points;
1534 while (current_length < track_length) {
1537 current_length += current_step;
1539 if (current_length > track_length)
1542 current_length_ratio = current_length / track_length;
1544 Double_t current_x = x + current_length_ratio * x_vec_from_in_to_out;
1545 Double_t current_y = y + current_length_ratio * y_vec_from_in_to_out;
1546 Double_t current_z = z + current_length_ratio * z_vec_from_in_to_out;
1548 collision_points.push_back(
CollPoint(current_x, current_y, current_z));
1553 for (
size_t icoll = 0; icoll < collision_points.size(); ++icoll) {
1555 Double_t xcoll = collision_points[icoll].x;
1556 Double_t ycoll = collision_points[icoll].y;
1557 Double_t zcoll = collision_points[icoll].z;
1570 xmean = p0_xmean + p1_xmean * zdist + p2_xmean * zdist * zdist + p3_xmean * zdist * zdist * zdist;
1571 sigma = p0_sigma + p1_sigma * zdist + p2_sigma * zdist * zdist + p3_sigma * zdist * zdist * zdist
1572 + p4_sigma * zdist * zdist * zdist * zdist + p5_sigma * zdist * zdist * zdist * zdist * zdist;
1575 Int_t n_electrons_cluster =
gRandom->Landau(1.027, 0.11);
1576 if (n_electrons_cluster < 1)
1577 n_electrons_cluster = 1;
1578 if (n_electrons_cluster > 6)
1579 n_electrons_cluster = 6;
1585 std::sqrt((xcoll - x) * (xcoll - x) + (ycoll - y) * (ycoll - y) + (zcoll - z) * (zcoll - z));
1587 dist_from_start = std::sqrt((xcoll - x_out) * (xcoll - x_out) + (ycoll - y_out) * (ycoll - y_out)
1588 + (zcoll - z_out) * (zcoll - z_out));
1590 Int_t segment = (
Int_t)(dist_from_start / track_length * n_track_segments);
1591 if (segment >= n_track_segments)
1592 segment = n_track_segments - 1;
1595 for (
Int_t ielectron = 0; ielectron < n_electrons_cluster; ++ielectron) {
1602 if (gain_gem1 < 1.0)
1604 if (gain_gem2 < 1.0)
1606 if (gain_gem3 < 1.0)
1611 if (zdist < level1) {
1614 if (zdist >= level1 && zdist < level2) {
1615 total_gain = gain_gem3;
1617 if (zdist >= level2 && zdist < level3) {
1618 total_gain = gain_gem3 * gain_gem2;
1620 if (zdist >= level3) {
1621 total_gain = gain_gem3 * gain_gem2 * gain_gem1;
1624 seg_local[segment] += total_gain;
1632 double x_readout, y_readout;
1634 for (
int igain = 0; igain < total_gain; ++igain) {
1638 x_readout =
gRandom->Gaus(xcoll + xmean, sigma);
1640 x_readout =
gRandom->Gaus(xcoll - xmean, sigma);
1643 y_readout =
gRandom->Gaus(ycoll, sigma);
1645 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1647 if (!
StripLayers[ilayer].IsPointInsideStripLayer(x_readout, y_readout))
1650 Double_t strip_pos =
StripLayers[ilayer].ConvertPointToStripPosition(x_readout, y_readout);
1652 Double_t dstrip = strip_pos - (int)strip_pos;
1653 if (layer_vertical[ilayer]) {
1655 if (dstrip >= 0.4 && dstrip < 0.6)
1659 if (dstrip >= 0.3 && dstrip < 0.7)
1665 if (strip_num >= 0 && strip_num < (
Int_t)strip_acc[ilayer].size()) {
1666 strip_acc[ilayer][strip_num] += 1.0;
1667 if (strip_num < acc_min[ilayer])
1668 acc_min[ilayer] = strip_num;
1669 if (strip_num > acc_max[ilayer])
1670 acc_max[ilayer] = strip_num;
1673 cluster_layers[ilayer].AddStrip(strip_num, 1.0);
1691 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1692 for (
Int_t istrip = acc_min[ilayer]; istrip <= acc_max[ilayer]; ++istrip) {
1693 if (strip_acc[ilayer][istrip] > 0.0)
1694 cluster_layers[ilayer].AddStrip(istrip, strip_acc[ilayer][istrip]);
1704 const vector<Int_t>& seg_used = use_external_segs ? segs : seg_local;
1720 drift_direction = 1;
1726 Double_t max_segment_val = *(std::max_element(seg_used.begin(), seg_used.end()));
1730 for (
size_t i = 0;
i < seg_used.size(); ++
i)
1731 total_charge += seg_used[
i];
1736 std::vector<float> input_data;
1737 input_data.reserve(n_ann_inputs);
1738 input_data.push_back(
static_cast<float>(px_norm));
1739 input_data.push_back(
static_cast<float>(py_norm));
1740 input_data.push_back(
static_cast<float>(pz_norm));
1741 input_data.push_back(
static_cast<float>(drift_direction));
1742 input_data.push_back(
static_cast<float>(bfield_used));
1743 for (
Int_t iseg = 0; iseg < n_segs_features; ++iseg)
1744 input_data.push_back((max_segment_val > 0.0) ?
static_cast<float>(seg_used[iseg] / max_segment_val) : 0.0f);
1746 if (total_charge > 0.0) {
1748 const Int_t center_strip_index = n_ann_strips / 2;
1751 auto process_layer = [&](
Int_t ilayer) {
1753 if (!
StripLayers[ilayer].IsPointInsideStripLayer(x_c, y_c))
1757 if (n_strips_in_layer <= 0)
1763 Double_t center_frac = center_pos - center_strip;
1770 std::vector<float> layer_input = input_data;
1771 layer_input.push_back(
static_cast<float>(strip_layer));
1772 layer_input.push_back(
static_cast<float>(strip_order));
1773 layer_input.push_back(
static_cast<float>(center_frac));
1776 const auto strip_values = ann_model->
Predict(layer_input);
1777 if (strip_values.size() !=
static_cast<std::size_t
>(n_ann_strips)) {
1778 LOG(error) <<
"BmnGemStripModule::"
1779 <<
"AddRealPointFull_ANNStripGenerator_Fdeep"
1780 <<
"(): model output size = " << strip_values.size() <<
", expected " << n_ann_strips;
1786 for (
Int_t istrip = 0; istrip < n_ann_strips; ++istrip)
1787 sum_norm += strip_values.at(istrip);
1790 const Double_t ann_correction_lower = 0.8;
1791 const Double_t ann_correction_upper = 0.6;
1797 signal_scale = (total_charge / sum_norm) * ann_correction;
1799 Double_t threshold = 0.0001 * total_charge;
1802 for (
Int_t istrip = 0; istrip < n_ann_strips; ++istrip) {
1803 Double_t content = strip_values.at(istrip) * signal_scale;
1804 if (content <= threshold)
1807 Int_t strip_num = center_strip - center_strip_index + istrip;
1808 if (strip_num < 0 || strip_num >= n_strips_in_layer)
1811 cluster_layers[ilayer].AddStrip(strip_num, content);
1817 if (kParallelANNLayers && n_strip_layers > 1) {
1818 std::vector<std::thread> layer_threads;
1819 for (
Int_t ilayer = 1; ilayer < n_strip_layers; ++ilayer)
1820 layer_threads.emplace_back(process_layer, ilayer);
1822 for (
auto& th : layer_threads)
1825 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer)
1826 process_layer(ilayer);
1835 if (use_external_segs)
1843 vector<Double_t> cluster_mean_position(n_strip_layers, 0.0);
1844 vector<Double_t> cluster_total_signal(n_strip_layers, 0.0);
1846 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1848 if (cluster_layers[ilayer].GetClusterSize() > 0) {
1850 for (
int i = 0;
i < cluster_layers[ilayer].GetClusterSize(); ++
i) {
1851 cluster_mean_position[ilayer] += (cluster_layers[ilayer].Strips[
i] + 0.5)
1852 * cluster_layers[ilayer].Signals[
i];
1853 cluster_total_signal[ilayer] += cluster_layers[ilayer].Signals[
i];
1855 cluster_mean_position[ilayer] /= cluster_total_signal[ilayer];
1858 cluster_layers[ilayer].MeanPosition = cluster_mean_position[ilayer];
1859 cluster_layers[ilayer].TotalSignal = cluster_total_signal[ilayer];
1864 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1865 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x, y);
1868 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1869 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x_out, y_out);
1874 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1875 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x_out, y_out);
1878 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1879 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x, y);
1884 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1885 cluster_layers[ilayer].PositionResidual =
1886 cluster_layers[ilayer].MeanPosition - cluster_layers[ilayer].OriginPosition;
1887 cluster_layers[ilayer].SetType(
StripLayers[ilayer].GetType());
1894 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1899 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1906 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1907 for (
size_t ielement = 0; ielement < cluster_layers[ilayer].Strips.size(); ++ielement) {
1908 Int_t strip_num = cluster_layers[ilayer].Strips.at(ielement);
1909 Double_t strip_signal = cluster_layers[ilayer].Signals.at(ielement);
1910 StripLayers[ilayer].AddStripSignal(strip_num, strip_signal);
1916 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
1917 for (
size_t ielement = 0; ielement < cluster_layers[ilayer].Strips.size(); ++ielement) {
1918 Int_t strip_num = cluster_layers[ilayer].Strips.at(ielement);
1919 Double_t strip_signal = cluster_layers[ilayer].Signals.at(ielement);
1920 StripLayers[ilayer].AddLinkToStripMatch(strip_num, strip_signal / cluster_layers[ilayer].TotalSignal,
1953 const Bool_t kParallelANNLayers =
true;
1957 const Int_t n_track_segments = 64;
1958 const Int_t n_segs_features = n_track_segments;
1959 const Int_t n_ann_inputs = 5 + n_segs_features + 3;
1960 Int_t n_ann_strips = 0;
1966 std::shared_ptr<const BmnGemStripFdeepModel> ann_holder;
1968 if (!onlyStandard) {
1970 ann_model = ann_holder.get();
1972 static std::mutex checked_mutex;
1974 std::pair<std::shared_ptr<const BmnGemStripFdeepModel>, std::string>>
1977 std::lock_guard<std::mutex> lock(checked_mutex);
1979 LOG(warn) <<
"BmnGemStripModule::" << __func__
1980 <<
"(): fdeep model is not available, the standard method is used";
1982 auto it = checked.find(ann_model);
1983 if (it == checked.end()) {
1986 why =
"input " + std::to_string(ann_model->
GetInputDim()) +
", expected "
1987 + std::to_string(n_ann_inputs);
1991 LOG(info) <<
"BmnGemStripModule::" << __func__ <<
"(): fdeep model " << ann_model->
GetFilePath()
1992 <<
" is used (ANN for |theta| < " << maxThetaAngle <<
" deg, window "
1994 it = checked.emplace(ann_model, std::make_pair(ann_holder, why)).first;
1996 if (!it->second.second.empty()) {
1997 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): the model " << ann_model->
GetFilePath()
1998 <<
" is not suitable (" << it->second.second <<
"), the standard method is used";
1999 ann_model =
nullptr;
2009 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): Point (" << x <<
" : " << y <<
" : " << z
2010 <<
") is out of the readout plane or inside a dead zone";
2015 Int_t pdg = pdg_code;
2023 if (points && mctracks && refID >= 0 && refID < points->GetEntriesFast()) {
2025 if (point && point->GetTrackID() >= 0 && point->GetTrackID() < mctracks->
GetEntriesFast())
2032 static std::atomic<bool> no_mc_reported{
false};
2033 if (!no_mc_reported.exchange(
true))
2034 LOG(warn) <<
"BmnGemStripModule::" << __func__
2035 <<
"(): pdg_code = 0 and the MC track is not available (no GemDigitizer or MC point), "
2036 "the He4 mass is used (this warning is printed once)";
2043 Double_t mnoc = 1.0, mass = 3.7283999;
2045 mass = part->
Mass();
2046 if (mass > 0.0001) {
2061 Double_t z_distance_from_in_to_out;
2071 if (z_distance_from_in_to_out <= 0.0) {
2072 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): Point (" << x <<
" : " << y <<
" : " << z
2073 <<
") has a track with an incorrect length";
2078 Double_t vector_coeff =
fabs(z_distance_from_in_to_out / pz);
2081 Double_t x_vec_from_in_to_out = vector_coeff * px;
2082 Double_t y_vec_from_in_to_out = vector_coeff * py;
2083 Double_t z_vec_from_in_to_out = vector_coeff * pz;
2086 Double_t x_out = x + x_vec_from_in_to_out;
2087 Double_t y_out = y + y_vec_from_in_to_out;
2088 Double_t z_out = z + z_vec_from_in_to_out;
2092 if (x_out < XMinModule || x_out >
XMaxModule) {
2098 x_vec_from_in_to_out = x_out - x;
2099 vector_coeff = x_vec_from_in_to_out / px;
2101 y_vec_from_in_to_out = vector_coeff * py;
2102 z_vec_from_in_to_out = vector_coeff * pz;
2104 y_out = y + y_vec_from_in_to_out;
2105 z_out = z + z_vec_from_in_to_out;
2108 if (y_out < YMinModule || y_out >
YMaxModule) {
2114 y_vec_from_in_to_out = y_out - y;
2115 vector_coeff = y_vec_from_in_to_out / py;
2117 x_vec_from_in_to_out = vector_coeff * px;
2118 z_vec_from_in_to_out = vector_coeff * pz;
2120 x_out = x + x_vec_from_in_to_out;
2121 z_out = z + z_vec_from_in_to_out;
2132 std::sqrt((x_vec_from_in_to_out) * (x_vec_from_in_to_out) + (y_vec_from_in_to_out) * (y_vec_from_in_to_out)
2133 + (z_vec_from_in_to_out) * (z_vec_from_in_to_out));
2139 const Bool_t useANN = (theta_deg_abs < maxThetaAngle) && ann_model;
2142 const Bool_t use_external_segs = useANN && !segs.empty();
2143 if (use_external_segs && segs.size() <
static_cast<size_t>(n_segs_features)) {
2144 LOG(error) <<
"BmnGemStripModule::" << __func__ <<
"(): segment vector size = " << segs.size()
2145 <<
", the model requires " << n_segs_features;
2176 vector<StripCluster> cluster_layers(n_strip_layers,
StripCluster());
2179 vector<Int_t> seg_local(n_track_segments, 0);
2187 constexpr Bool_t kExactGRandomSequence =
false;
2188 constexpr Long64_t kElectronsPerTask = 4096;
2189 constexpr Long64_t kMinElectronsForParallel = 20000;
2191 struct AvalancheTask
2199 std::vector<AvalancheTask> aval_tasks;
2201 std::vector<Double_t> exact_x, exact_y;
2208 std::vector<std::thread> workers;
2211 std::condition_variable cv_start;
2212 std::condition_variable cv_done;
2213 const std::function<void(
size_t)>* job =
nullptr;
2215 std::atomic<size_t> next{0};
2216 size_t generation = 0;
2220 explicit ThreadPool(
size_t n_workers)
2222 workers.reserve(n_workers);
2223 for (
size_t i = 0;
i < n_workers; ++
i)
2224 workers.emplace_back([
this] { Loop(); });
2230 std::lock_guard<std::mutex> lk(mtx);
2233 cv_start.notify_all();
2234 for (
auto& w : workers)
2240 for (
size_t i = next.fetch_add(1);
i < n_items;
i = next.fetch_add(1))
2249 std::unique_lock<std::mutex> lk(mtx);
2250 cv_start.wait(lk, [&] {
return stop || generation != seen; });
2257 std::lock_guard<std::mutex> lk(mtx);
2259 cv_done.notify_one();
2265 void Run(
size_t n,
const std::function<
void(
size_t)>& func)
2269 if (workers.empty() ||
n == 1) {
2270 for (
size_t i = 0;
i <
n; ++
i)
2275 std::lock_guard<std::mutex> run_lock(run_mtx);
2277 std::lock_guard<std::mutex> lk(mtx);
2281 n_busy = workers.size();
2284 cv_start.notify_all();
2288 std::unique_lock<std::mutex> lk(mtx);
2289 cv_done.wait(lk, [&] {
return n_busy == 0; });
2295 static ThreadPool pool(std::max(1u, std::thread::hardware_concurrency()) - 1);
2297 auto parallel_for = [](
size_t n,
const std::function<void(
size_t)>& func) { pool.Run(
n, func); };
2300 if (!use_external_segs) {
2303 Double_t current_length_ratio = 0.0;
2307 std::vector<CollPoint> collision_points;
2313 while (current_length < track_length) {
2316 current_length += current_step;
2318 if (current_length > track_length)
2321 current_length_ratio = current_length / track_length;
2323 Double_t current_x = x + current_length_ratio * x_vec_from_in_to_out;
2324 Double_t current_y = y + current_length_ratio * y_vec_from_in_to_out;
2325 Double_t current_z = z + current_length_ratio * z_vec_from_in_to_out;
2327 collision_points.push_back(
CollPoint(current_x, current_y, current_z));
2332 for (
size_t icoll = 0; icoll < collision_points.size(); ++icoll) {
2334 Double_t xcoll = collision_points[icoll].x;
2335 Double_t ycoll = collision_points[icoll].y;
2336 Double_t zcoll = collision_points[icoll].z;
2349 xmean = p0_xmean + p1_xmean * zdist + p2_xmean * zdist * zdist + p3_xmean * zdist * zdist * zdist;
2350 sigma = p0_sigma + p1_sigma * zdist + p2_sigma * zdist * zdist + p3_sigma * zdist * zdist * zdist
2351 + p4_sigma * zdist * zdist * zdist * zdist + p5_sigma * zdist * zdist * zdist * zdist * zdist;
2354 Int_t n_electrons_cluster =
gRandom->Landau(1.027, 0.11);
2355 if (n_electrons_cluster < 1)
2356 n_electrons_cluster = 1;
2357 if (n_electrons_cluster > 6)
2358 n_electrons_cluster = 6;
2364 std::sqrt((xcoll - x) * (xcoll - x) + (ycoll - y) * (ycoll - y) + (zcoll - z) * (zcoll - z));
2366 dist_from_start = std::sqrt((xcoll - x_out) * (xcoll - x_out) + (ycoll - y_out) * (ycoll - y_out)
2367 + (zcoll - z_out) * (zcoll - z_out));
2369 Int_t segment = (
Int_t)(dist_from_start / track_length * n_track_segments);
2370 if (segment >= n_track_segments)
2371 segment = n_track_segments - 1;
2374 for (
Int_t ielectron = 0; ielectron < n_electrons_cluster; ++ielectron) {
2381 if (gain_gem1 < 1.0)
2383 if (gain_gem2 < 1.0)
2385 if (gain_gem3 < 1.0)
2390 if (zdist < level1) {
2393 if (zdist >= level1 && zdist < level2) {
2394 total_gain = gain_gem3;
2396 if (zdist >= level2 && zdist < level3) {
2397 total_gain = gain_gem3 * gain_gem2;
2399 if (zdist >= level3) {
2400 total_gain = gain_gem3 * gain_gem2 * gain_gem1;
2403 seg_local[segment] += total_gain;
2416 if (kExactGRandomSequence) {
2418 for (
int igain = 0; igain < total_gain; ++igain) {
2419 exact_x.push_back(
gRandom->Gaus(x_center, sigma));
2420 exact_y.push_back(
gRandom->Gaus(ycoll, sigma));
2424 for (
Long64_t done = 0; done < total_gain; done += kElectronsPerTask) {
2425 aval_tasks.push_back({x_center, ycoll, sigma, n_aval_electrons + done,
2426 std::min<Long64_t>(kElectronsPerTask, total_gain - done)});
2428 n_aval_electrons += total_gain;
2442 const size_t n_electrons = kExactGRandomSequence ? exact_x.size() :
static_cast<size_t>(n_aval_electrons);
2444 if (n_electrons > 0) {
2446 const Bool_t run_parallel =
static_cast<Long64_t>(n_electrons) >= kMinElectronsForParallel;
2447 const size_t chunk_size =
static_cast<size_t>(kElectronsPerTask);
2450 std::vector<char> layer_vertical(n_strip_layers);
2451 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer)
2457 std::vector<Int_t> lo;
2458 std::vector<std::vector<Int_t>> cnt;
2460 const size_t n_tasks =
2461 kExactGRandomSequence ? (n_electrons + chunk_size - 1) / chunk_size : aval_tasks.size();
2462 std::vector<TaskCounts> task_counts(n_tasks);
2465 auto count_electron = [&](TaskCounts& tc,
Double_t x_readout,
Double_t y_readout) {
2466 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
2470 if (!
StripLayers[ilayer].IsPointInsideStripLayer(x_readout, y_readout))
2473 Double_t strip_pos =
StripLayers[ilayer].ConvertPointToStripPosition(x_readout, y_readout);
2475 Double_t dstrip = strip_pos - (int)strip_pos;
2476 if (layer_vertical[ilayer]) {
2478 if (dstrip >= 0.4 && dstrip < 0.6)
2482 if (dstrip >= 0.3 && dstrip < 0.7)
2488 std::vector<Int_t>& cnt = tc.cnt[ilayer];
2489 Int_t& lo = tc.lo[ilayer];
2493 }
else if (strip < lo) {
2494 cnt.insert(cnt.begin(), lo - strip, 0);
2496 }
else if (strip >= lo +
static_cast<Int_t>(cnt.size())) {
2497 cnt.resize(strip - lo + 1, 0);
2503 auto init_counts = [&](TaskCounts& tc) {
2504 tc.lo.assign(n_strip_layers, 0);
2505 tc.cnt.assign(n_strip_layers, std::vector<Int_t>());
2508 if (kExactGRandomSequence) {
2510 auto process_chunk = [&](
size_t ichunk) {
2511 TaskCounts& tc = task_counts[ichunk];
2513 const size_t begin = ichunk * chunk_size;
2514 const size_t end = std::min(n_electrons, begin + chunk_size);
2515 for (
size_t ie = begin; ie < end; ++ie)
2516 count_electron(tc, exact_x[ie], exact_y[ie]);
2520 parallel_for(n_tasks, process_chunk);
2522 for (
size_t ichunk = 0; ichunk < n_tasks; ++ichunk)
2523 process_chunk(ichunk);
2535 const UInt_t base_seed =
static_cast<UInt_t
>(
gRandom->Integer(0xFFFFFFFFu));
2545 auto process_task = [&](
size_t itask) {
2546 const AvalancheTask& t = aval_tasks[itask];
2547 TaskCounts& tc = task_counts[itask];
2549 std::seed_seq seq{base_seed,
static_cast<UInt_t
>(itask)};
2550 std::mt19937_64 rng(seq);
2551 std::normal_distribution<Double_t> gaus(0.0, 1.0);
2554 const Double_t x_readout = t.xcenter + t.sigma * gaus(rng);
2555 const Double_t y_readout = t.ycenter + t.sigma * gaus(rng);
2558 const size_t ie = first_electron +
static_cast<size_t>(t.offset +
i);
2563 count_electron(tc, x_readout, y_readout);
2568 parallel_for(n_tasks, process_task);
2570 for (
size_t itask = 0; itask < n_tasks; ++itask)
2571 process_task(itask);
2576 auto fill_layer = [&](
size_t ilayer) {
2578 const Int_t n_strips_in_layer = std::max(0,
StripLayers[ilayer].GetNStrips());
2579 std::vector<Double_t> strip_acc(n_strips_in_layer, 0.0);
2580 Int_t acc_min = std::numeric_limits<Int_t>::max();
2583 for (
size_t itask = 0; itask < n_tasks; ++itask) {
2584 const Int_t lo = task_counts[itask].lo[ilayer];
2585 const std::vector<Int_t>& cnt = task_counts[itask].cnt[ilayer];
2586 for (
size_t i = 0;
i < cnt.size(); ++
i) {
2590 if (strip >= 0 && strip < n_strips_in_layer) {
2591 strip_acc[strip] += cnt[
i];
2592 if (strip < acc_min)
2594 if (strip > acc_max)
2603 for (
Int_t istrip = acc_min; istrip <= acc_max; ++istrip) {
2604 if (strip_acc[istrip] > 0.0)
2605 cluster.
AddStrip(istrip, strip_acc[istrip]);
2610 parallel_for(
static_cast<size_t>(n_strip_layers), fill_layer);
2612 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer)
2622 const vector<Int_t>& seg_used = use_external_segs ? segs : seg_local;
2638 drift_direction = 1;
2644 Double_t max_segment_val = *(std::max_element(seg_used.begin(), seg_used.end()));
2648 for (
size_t i = 0;
i < seg_used.size(); ++
i)
2649 total_charge += seg_used[
i];
2654 std::vector<float> input_data;
2655 input_data.reserve(n_ann_inputs);
2656 input_data.push_back(
static_cast<float>(px_norm));
2657 input_data.push_back(
static_cast<float>(py_norm));
2658 input_data.push_back(
static_cast<float>(pz_norm));
2659 input_data.push_back(
static_cast<float>(drift_direction));
2660 input_data.push_back(
static_cast<float>(bfield_used));
2661 for (
Int_t iseg = 0; iseg < n_segs_features; ++iseg)
2662 input_data.push_back((max_segment_val > 0.0) ?
static_cast<float>(seg_used[iseg] / max_segment_val) : 0.0f);
2664 if (total_charge > 0.0) {
2666 const Int_t center_strip_index = n_ann_strips / 2;
2669 auto process_layer = [&](
size_t ilayer) {
2671 if (!
StripLayers[ilayer].IsPointInsideStripLayer(x_c, y_c))
2675 if (n_strips_in_layer <= 0)
2681 Double_t center_frac = center_pos - center_strip;
2688 std::vector<float> layer_input = input_data;
2689 layer_input.push_back(
static_cast<float>(strip_layer));
2690 layer_input.push_back(
static_cast<float>(strip_order));
2691 layer_input.push_back(
static_cast<float>(center_frac));
2694 const auto strip_values = ann_model->
Predict(layer_input);
2695 if (strip_values.size() !=
static_cast<std::size_t
>(n_ann_strips)) {
2696 LOG(error) <<
"BmnGemStripModule::"
2697 <<
"AddRealPointFull_ANNStripGenerator_Fdeep_Parallel"
2698 <<
"(): model output size = " << strip_values.size() <<
", expected " << n_ann_strips;
2704 for (
Int_t istrip = 0; istrip < n_ann_strips; ++istrip)
2705 sum_norm += strip_values.at(istrip);
2708 const Double_t ann_correction_lower = 0.8;
2709 const Double_t ann_correction_upper = 0.6;
2715 signal_scale = (total_charge / sum_norm) * ann_correction;
2717 Double_t threshold = 0.0001 * total_charge;
2720 for (
Int_t istrip = 0; istrip < n_ann_strips; ++istrip) {
2721 Double_t content = strip_values.at(istrip) * signal_scale;
2722 if (content <= threshold)
2725 Int_t strip_num = center_strip - center_strip_index + istrip;
2726 if (strip_num < 0 || strip_num >= n_strips_in_layer)
2729 cluster_layers[ilayer].AddStrip(strip_num, content);
2734 if (kParallelANNLayers)
2735 parallel_for(
static_cast<size_t>(n_strip_layers), process_layer);
2737 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer)
2738 process_layer(ilayer);
2746 if (use_external_segs)
2754 vector<Double_t> cluster_mean_position(n_strip_layers, 0.0);
2755 vector<Double_t> cluster_total_signal(n_strip_layers, 0.0);
2757 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
2759 if (cluster_layers[ilayer].GetClusterSize() > 0) {
2761 for (
int i = 0;
i < cluster_layers[ilayer].GetClusterSize(); ++
i) {
2762 cluster_mean_position[ilayer] += (cluster_layers[ilayer].Strips[
i] + 0.5)
2763 * cluster_layers[ilayer].Signals[
i];
2764 cluster_total_signal[ilayer] += cluster_layers[ilayer].Signals[
i];
2766 cluster_mean_position[ilayer] /= cluster_total_signal[ilayer];
2769 cluster_layers[ilayer].MeanPosition = cluster_mean_position[ilayer];
2770 cluster_layers[ilayer].TotalSignal = cluster_total_signal[ilayer];
2775 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
2776 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x, y);
2779 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
2780 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x_out, y_out);
2785 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
2786 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x_out, y_out);
2789 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
2790 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x, y);
2795 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
2796 cluster_layers[ilayer].PositionResidual =
2797 cluster_layers[ilayer].MeanPosition - cluster_layers[ilayer].OriginPosition;
2798 cluster_layers[ilayer].SetType(
StripLayers[ilayer].GetType());
2805 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
2810 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
2817 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
2818 for (
size_t ielement = 0; ielement < cluster_layers[ilayer].Strips.size(); ++ielement) {
2819 Int_t strip_num = cluster_layers[ilayer].Strips.at(ielement);
2820 Double_t strip_signal = cluster_layers[ilayer].Signals.at(ielement);
2821 StripLayers[ilayer].AddStripSignal(strip_num, strip_signal);
2827 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
2828 for (
size_t ielement = 0; ielement < cluster_layers[ilayer].Strips.size(); ++ielement) {
2829 Int_t strip_num = cluster_layers[ilayer].Strips.at(ielement);
2830 Double_t strip_signal = cluster_layers[ilayer].Signals.at(ielement);
2831 StripLayers[ilayer].AddLinkToStripMatch(strip_num, strip_signal / cluster_layers[ilayer].TotalSignal,
2869 const Int_t n_track_segments = 64;
2870 const Int_t n_segs_features = n_track_segments;
2871 const Int_t n_common_inputs = 5 + n_segs_features;
2872 const Int_t n_layer_inputs = 3;
2873 Int_t n_ann_strips = 0;
2879 std::shared_ptr<const BmnGemStripMLPModel> mlp_holder;
2881 if (!onlyStandard) {
2883 mlp_model = mlp_holder.get();
2885 static std::mutex checked_mutex;
2886 static std::map<const BmnGemStripMLPModel*, std::pair<std::shared_ptr<const BmnGemStripMLPModel>, std::string>>
2889 std::lock_guard<std::mutex> lock(checked_mutex);
2891 LOG(warn) <<
"BmnGemStripModule::" << __func__
2892 <<
"(): MLP model is not available, the standard method is used";
2894 auto it = checked.find(mlp_model);
2895 if (it == checked.end()) {
2896 std::vector<std::string> expected = {
"px",
"py",
"pz",
"drift",
"bfield"};
2897 for (
Int_t iseg = 0; iseg < n_segs_features; ++iseg)
2898 expected.push_back(
"s" + std::to_string(iseg));
2899 expected.insert(expected.end(), {
"strip_layer",
"strip_order",
"center_frac"});
2909 LOG(info) <<
"BmnGemStripModule::" << __func__ <<
"(): MLP model " << mlp_model->
GetFilePath()
2910 <<
" is used (ANN for |theta| < " << maxThetaAngle <<
" deg, window "
2912 }
else if (why.empty())
2913 why =
"unknown reason";
2914 it = checked.emplace(mlp_model, std::make_pair(mlp_holder, why)).first;
2916 if (!it->second.second.empty()) {
2917 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): the model " << mlp_model->
GetFilePath()
2918 <<
" is not suitable (" << it->second.second <<
"), the standard method is used";
2919 mlp_model =
nullptr;
2929 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): Point (" << x <<
" : " << y <<
" : " << z
2930 <<
") is out of the readout plane or inside a dead zone";
2935 Int_t pdg = pdg_code;
2943 if (points && mctracks && refID >= 0 && refID < points->GetEntriesFast()) {
2945 if (point && point->GetTrackID() >= 0 && point->GetTrackID() < mctracks->
GetEntriesFast())
2952 static std::atomic<bool> no_mc_reported{
false};
2953 if (!no_mc_reported.exchange(
true))
2954 LOG(warn) <<
"BmnGemStripModule::" << __func__
2955 <<
"(): pdg_code = 0 and the MC track is not available (no GemDigitizer or MC point), "
2956 "the He4 mass is used (this warning is printed once)";
2963 Double_t mnoc = 1.0, mass = 3.7283999;
2965 mass = part->
Mass();
2966 if (mass > 0.0001) {
2981 Double_t z_distance_from_in_to_out;
2991 if (z_distance_from_in_to_out <= 0.0) {
2992 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): Point (" << x <<
" : " << y <<
" : " << z
2993 <<
") has a track with an incorrect length";
2998 Double_t vector_coeff =
fabs(z_distance_from_in_to_out / pz);
3001 Double_t x_vec_from_in_to_out = vector_coeff * px;
3002 Double_t y_vec_from_in_to_out = vector_coeff * py;
3003 Double_t z_vec_from_in_to_out = vector_coeff * pz;
3006 Double_t x_out = x + x_vec_from_in_to_out;
3007 Double_t y_out = y + y_vec_from_in_to_out;
3008 Double_t z_out = z + z_vec_from_in_to_out;
3012 if (x_out < XMinModule || x_out >
XMaxModule) {
3018 x_vec_from_in_to_out = x_out - x;
3019 vector_coeff = x_vec_from_in_to_out / px;
3021 y_vec_from_in_to_out = vector_coeff * py;
3022 z_vec_from_in_to_out = vector_coeff * pz;
3024 y_out = y + y_vec_from_in_to_out;
3025 z_out = z + z_vec_from_in_to_out;
3028 if (y_out < YMinModule || y_out >
YMaxModule) {
3034 y_vec_from_in_to_out = y_out - y;
3035 vector_coeff = y_vec_from_in_to_out / py;
3037 x_vec_from_in_to_out = vector_coeff * px;
3038 z_vec_from_in_to_out = vector_coeff * pz;
3040 x_out = x + x_vec_from_in_to_out;
3041 z_out = z + z_vec_from_in_to_out;
3052 std::sqrt((x_vec_from_in_to_out) * (x_vec_from_in_to_out) + (y_vec_from_in_to_out) * (y_vec_from_in_to_out)
3053 + (z_vec_from_in_to_out) * (z_vec_from_in_to_out));
3059 const Bool_t useANN = (theta_deg_abs < maxThetaAngle) && mlp_model;
3062 const Bool_t use_external_segs = useANN && !segs.empty();
3063 if (use_external_segs && segs.size() <
static_cast<size_t>(n_segs_features)) {
3064 LOG(error) <<
"BmnGemStripModule::" << __func__ <<
"(): segment vector size = " << segs.size()
3065 <<
", the model requires " << n_segs_features;
3096 vector<StripCluster> cluster_layers(n_strip_layers,
StripCluster());
3099 vector<Int_t> seg_local(n_track_segments, 0);
3105 vector<vector<Double_t>> strip_acc;
3106 vector<Int_t> acc_min, acc_max;
3107 vector<char> layer_vertical;
3109 strip_acc.resize(n_strip_layers);
3110 acc_min.assign(n_strip_layers, std::numeric_limits<Int_t>::max());
3111 acc_max.assign(n_strip_layers, -1);
3112 layer_vertical.assign(n_strip_layers, 0);
3113 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
3114 strip_acc[ilayer].assign(std::max(0,
StripLayers[ilayer].GetNStrips()), 0.0);
3120 if (!use_external_segs) {
3123 Double_t current_length_ratio = 0.0;
3127 std::vector<CollPoint> collision_points;
3133 while (current_length < track_length) {
3136 current_length += current_step;
3138 if (current_length > track_length)
3141 current_length_ratio = current_length / track_length;
3143 Double_t current_x = x + current_length_ratio * x_vec_from_in_to_out;
3144 Double_t current_y = y + current_length_ratio * y_vec_from_in_to_out;
3145 Double_t current_z = z + current_length_ratio * z_vec_from_in_to_out;
3147 collision_points.push_back(
CollPoint(current_x, current_y, current_z));
3152 for (
size_t icoll = 0; icoll < collision_points.size(); ++icoll) {
3154 Double_t xcoll = collision_points[icoll].x;
3155 Double_t ycoll = collision_points[icoll].y;
3156 Double_t zcoll = collision_points[icoll].z;
3169 xmean = p0_xmean + p1_xmean * zdist + p2_xmean * zdist * zdist + p3_xmean * zdist * zdist * zdist;
3170 sigma = p0_sigma + p1_sigma * zdist + p2_sigma * zdist * zdist + p3_sigma * zdist * zdist * zdist
3171 + p4_sigma * zdist * zdist * zdist * zdist + p5_sigma * zdist * zdist * zdist * zdist * zdist;
3174 Int_t n_electrons_cluster =
gRandom->Landau(1.027, 0.11);
3175 if (n_electrons_cluster < 1)
3176 n_electrons_cluster = 1;
3177 if (n_electrons_cluster > 6)
3178 n_electrons_cluster = 6;
3184 std::sqrt((xcoll - x) * (xcoll - x) + (ycoll - y) * (ycoll - y) + (zcoll - z) * (zcoll - z));
3186 dist_from_start = std::sqrt((xcoll - x_out) * (xcoll - x_out) + (ycoll - y_out) * (ycoll - y_out)
3187 + (zcoll - z_out) * (zcoll - z_out));
3189 Int_t segment = (
Int_t)(dist_from_start / track_length * n_track_segments);
3190 if (segment >= n_track_segments)
3191 segment = n_track_segments - 1;
3194 for (
Int_t ielectron = 0; ielectron < n_electrons_cluster; ++ielectron) {
3201 if (gain_gem1 < 1.0)
3203 if (gain_gem2 < 1.0)
3205 if (gain_gem3 < 1.0)
3210 if (zdist < level1) {
3213 if (zdist >= level1 && zdist < level2) {
3214 total_gain = gain_gem3;
3216 if (zdist >= level2 && zdist < level3) {
3217 total_gain = gain_gem3 * gain_gem2;
3219 if (zdist >= level3) {
3220 total_gain = gain_gem3 * gain_gem2 * gain_gem1;
3223 seg_local[segment] += total_gain;
3231 double x_readout, y_readout;
3233 for (
int igain = 0; igain < total_gain; ++igain) {
3237 x_readout =
gRandom->Gaus(xcoll + xmean, sigma);
3239 x_readout =
gRandom->Gaus(xcoll - xmean, sigma);
3242 y_readout =
gRandom->Gaus(ycoll, sigma);
3244 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
3246 if (!
StripLayers[ilayer].IsPointInsideStripLayer(x_readout, y_readout))
3249 Double_t strip_pos =
StripLayers[ilayer].ConvertPointToStripPosition(x_readout, y_readout);
3251 Double_t dstrip = strip_pos - (int)strip_pos;
3252 if (layer_vertical[ilayer]) {
3254 if (dstrip >= 0.4 && dstrip < 0.6)
3258 if (dstrip >= 0.3 && dstrip < 0.7)
3264 if (strip_num >= 0 && strip_num < (
Int_t)strip_acc[ilayer].size()) {
3265 strip_acc[ilayer][strip_num] += 1.0;
3266 if (strip_num < acc_min[ilayer])
3267 acc_min[ilayer] = strip_num;
3268 if (strip_num > acc_max[ilayer])
3269 acc_max[ilayer] = strip_num;
3272 cluster_layers[ilayer].AddStrip(strip_num, 1.0);
3290 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
3291 for (
Int_t istrip = acc_min[ilayer]; istrip <= acc_max[ilayer]; ++istrip) {
3292 if (strip_acc[ilayer][istrip] > 0.0)
3293 cluster_layers[ilayer].AddStrip(istrip, strip_acc[ilayer][istrip]);
3303 const vector<Int_t>& seg_used = use_external_segs ? segs : seg_local;
3319 drift_direction = 1;
3325 Double_t max_segment_val = *(std::max_element(seg_used.begin(), seg_used.end()));
3329 for (
size_t i = 0;
i < seg_used.size(); ++
i)
3330 total_charge += seg_used[
i];
3335 float common_input[n_common_inputs];
3336 common_input[0] =
static_cast<float>(px_norm);
3337 common_input[1] =
static_cast<float>(py_norm);
3338 common_input[2] =
static_cast<float>(pz_norm);
3339 common_input[3] =
static_cast<float>(drift_direction);
3340 common_input[4] =
static_cast<float>(bfield_used);
3341 for (
Int_t iseg = 0; iseg < n_segs_features; ++iseg)
3342 common_input[5 + iseg] =
3343 (max_segment_val > 0.0) ?
static_cast<float>(seg_used[iseg] / max_segment_val) : 0.0f;
3345 if (total_charge > 0.0) {
3347 const Int_t center_strip_index = n_ann_strips / 2;
3350 std::vector<Int_t> ann_layers;
3351 std::vector<Int_t> ann_center_strips;
3352 std::vector<Int_t> ann_n_strips;
3353 std::vector<float> ann_layer_inputs;
3354 ann_layers.reserve(n_strip_layers);
3355 ann_center_strips.reserve(n_strip_layers);
3356 ann_n_strips.reserve(n_strip_layers);
3357 ann_layer_inputs.reserve(n_strip_layers * n_layer_inputs);
3359 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
3362 if (!
StripLayers[ilayer].IsPointInsideStripLayer(x_c, y_c))
3366 if (n_strips_in_layer <= 0)
3372 Double_t center_frac = center_pos - center_strip;
3378 ann_layers.push_back(ilayer);
3379 ann_center_strips.push_back(center_strip);
3380 ann_n_strips.push_back(n_strips_in_layer);
3381 ann_layer_inputs.push_back(
static_cast<float>(strip_layer));
3382 ann_layer_inputs.push_back(
static_cast<float>(strip_order));
3383 ann_layer_inputs.push_back(
static_cast<float>(center_frac));
3387 Int_t n_ann_layers = ann_layers.size();
3388 std::vector<float> ann_strip_values(
static_cast<size_t>(n_ann_layers) * n_ann_strips);
3389 if (n_ann_layers > 0
3390 && !mlp_model->
PredictSplit(common_input, n_common_inputs, ann_layer_inputs.data(), n_ann_layers,
3391 ann_strip_values.data()))
3393 LOG(error) <<
"BmnGemStripModule::" << __func__ <<
"(): MLP prediction failed";
3397 for (
Int_t iann = 0; iann < n_ann_layers; ++iann) {
3398 const Int_t ilayer = ann_layers[iann];
3399 const Int_t center_strip = ann_center_strips[iann];
3400 const Int_t n_strips_in_layer = ann_n_strips[iann];
3401 const float* strip_values = ann_strip_values.data() +
static_cast<size_t>(iann) * n_ann_strips;
3405 for (
Int_t istrip = 0; istrip < n_ann_strips; ++istrip)
3406 sum_norm += strip_values[istrip];
3409 const Double_t ann_correction_lower = 0.8;
3410 const Double_t ann_correction_upper = 0.6;
3416 signal_scale = (total_charge / sum_norm) * ann_correction;
3418 Double_t threshold = 0.0001 * total_charge;
3421 for (
Int_t istrip = 0; istrip < n_ann_strips; ++istrip) {
3422 Double_t content = strip_values[istrip] * signal_scale;
3423 if (content <= threshold)
3426 Int_t strip_num = center_strip - center_strip_index + istrip;
3427 if (strip_num < 0 || strip_num >= n_strips_in_layer)
3430 cluster_layers[ilayer].AddStrip(strip_num, content);
3440 if (use_external_segs)
3448 vector<Double_t> cluster_mean_position(n_strip_layers, 0.0);
3449 vector<Double_t> cluster_total_signal(n_strip_layers, 0.0);
3451 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
3453 if (cluster_layers[ilayer].GetClusterSize() > 0) {
3455 for (
int i = 0;
i < cluster_layers[ilayer].GetClusterSize(); ++
i) {
3456 cluster_mean_position[ilayer] += (cluster_layers[ilayer].Strips[
i] + 0.5)
3457 * cluster_layers[ilayer].Signals[
i];
3458 cluster_total_signal[ilayer] += cluster_layers[ilayer].Signals[
i];
3460 cluster_mean_position[ilayer] /= cluster_total_signal[ilayer];
3463 cluster_layers[ilayer].MeanPosition = cluster_mean_position[ilayer];
3464 cluster_layers[ilayer].TotalSignal = cluster_total_signal[ilayer];
3469 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
3470 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x, y);
3473 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
3474 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x_out, y_out);
3479 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
3480 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x_out, y_out);
3483 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
3484 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x, y);
3489 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
3490 cluster_layers[ilayer].PositionResidual =
3491 cluster_layers[ilayer].MeanPosition - cluster_layers[ilayer].OriginPosition;
3492 cluster_layers[ilayer].SetType(
StripLayers[ilayer].GetType());
3499 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
3504 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
3511 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
3512 for (
size_t ielement = 0; ielement < cluster_layers[ilayer].Strips.size(); ++ielement) {
3513 Int_t strip_num = cluster_layers[ilayer].Strips.at(ielement);
3514 Double_t strip_signal = cluster_layers[ilayer].Signals.at(ielement);
3515 StripLayers[ilayer].AddStripSignal(strip_num, strip_signal);
3521 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
3522 for (
size_t ielement = 0; ielement < cluster_layers[ilayer].Strips.size(); ++ielement) {
3523 Int_t strip_num = cluster_layers[ilayer].Strips.at(ielement);
3524 Double_t strip_signal = cluster_layers[ilayer].Signals.at(ielement);
3525 StripLayers[ilayer].AddLinkToStripMatch(strip_num, strip_signal / cluster_layers[ilayer].TotalSignal,
3561 const Int_t n_track_segments = 64;
3562 const Int_t n_segs_features = n_track_segments;
3563 const Int_t n_common_inputs = 5 + n_segs_features;
3564 const Int_t n_layer_inputs = 3;
3565 Int_t n_ann_strips = 0;
3571 std::shared_ptr<const BmnGemStripMLPModel> mlp_holder;
3573 if (!onlyStandard) {
3575 mlp_model = mlp_holder.get();
3577 static std::mutex checked_mutex;
3578 static std::map<const BmnGemStripMLPModel*, std::pair<std::shared_ptr<const BmnGemStripMLPModel>, std::string>>
3581 std::lock_guard<std::mutex> lock(checked_mutex);
3583 LOG(warn) <<
"BmnGemStripModule::" << __func__
3584 <<
"(): MLP model is not available, the standard method is used";
3586 auto it = checked.find(mlp_model);
3587 if (it == checked.end()) {
3588 std::vector<std::string> expected = {
"px",
"py",
"pz",
"drift",
"bfield"};
3589 for (
Int_t iseg = 0; iseg < n_segs_features; ++iseg)
3590 expected.push_back(
"s" + std::to_string(iseg));
3591 expected.insert(expected.end(), {
"strip_layer",
"strip_order",
"center_frac"});
3601 LOG(info) <<
"BmnGemStripModule::" << __func__ <<
"(): MLP model " << mlp_model->
GetFilePath()
3602 <<
" is used (ANN for |theta| < " << maxThetaAngle <<
" deg, window "
3604 }
else if (why.empty())
3605 why =
"unknown reason";
3606 it = checked.emplace(mlp_model, std::make_pair(mlp_holder, why)).first;
3608 if (!it->second.second.empty()) {
3609 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): the model " << mlp_model->
GetFilePath()
3610 <<
" is not suitable (" << it->second.second <<
"), the standard method is used";
3611 mlp_model =
nullptr;
3621 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): Point (" << x <<
" : " << y <<
" : " << z
3622 <<
") is out of the readout plane or inside a dead zone";
3627 Int_t pdg = pdg_code;
3635 if (points && mctracks && refID >= 0 && refID < points->GetEntriesFast()) {
3637 if (point && point->GetTrackID() >= 0 && point->GetTrackID() < mctracks->
GetEntriesFast())
3644 static std::atomic<bool> no_mc_reported{
false};
3645 if (!no_mc_reported.exchange(
true))
3646 LOG(warn) <<
"BmnGemStripModule::" << __func__
3647 <<
"(): pdg_code = 0 and the MC track is not available (no GemDigitizer or MC point), "
3648 "the He4 mass is used (this warning is printed once)";
3655 Double_t mnoc = 1.0, mass = 3.7283999;
3657 mass = part->
Mass();
3658 if (mass > 0.0001) {
3673 Double_t z_distance_from_in_to_out;
3683 if (z_distance_from_in_to_out <= 0.0) {
3684 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): Point (" << x <<
" : " << y <<
" : " << z
3685 <<
") has a track with an incorrect length";
3690 Double_t vector_coeff =
fabs(z_distance_from_in_to_out / pz);
3693 Double_t x_vec_from_in_to_out = vector_coeff * px;
3694 Double_t y_vec_from_in_to_out = vector_coeff * py;
3695 Double_t z_vec_from_in_to_out = vector_coeff * pz;
3698 Double_t x_out = x + x_vec_from_in_to_out;
3699 Double_t y_out = y + y_vec_from_in_to_out;
3700 Double_t z_out = z + z_vec_from_in_to_out;
3704 if (x_out < XMinModule || x_out >
XMaxModule) {
3710 x_vec_from_in_to_out = x_out - x;
3711 vector_coeff = x_vec_from_in_to_out / px;
3713 y_vec_from_in_to_out = vector_coeff * py;
3714 z_vec_from_in_to_out = vector_coeff * pz;
3716 y_out = y + y_vec_from_in_to_out;
3717 z_out = z + z_vec_from_in_to_out;
3720 if (y_out < YMinModule || y_out >
YMaxModule) {
3726 y_vec_from_in_to_out = y_out - y;
3727 vector_coeff = y_vec_from_in_to_out / py;
3729 x_vec_from_in_to_out = vector_coeff * px;
3730 z_vec_from_in_to_out = vector_coeff * pz;
3732 x_out = x + x_vec_from_in_to_out;
3733 z_out = z + z_vec_from_in_to_out;
3744 std::sqrt((x_vec_from_in_to_out) * (x_vec_from_in_to_out) + (y_vec_from_in_to_out) * (y_vec_from_in_to_out)
3745 + (z_vec_from_in_to_out) * (z_vec_from_in_to_out));
3751 const Bool_t useANN = (theta_deg_abs < maxThetaAngle) && mlp_model;
3754 const Bool_t use_external_segs = useANN && !segs.empty();
3755 if (use_external_segs && segs.size() <
static_cast<size_t>(n_segs_features)) {
3756 LOG(error) <<
"BmnGemStripModule::" << __func__ <<
"(): segment vector size = " << segs.size()
3757 <<
", the model requires " << n_segs_features;
3788 vector<StripCluster> cluster_layers(n_strip_layers,
StripCluster());
3791 vector<Int_t> seg_local(n_track_segments, 0);
3799 constexpr Bool_t kExactGRandomSequence =
false;
3800 constexpr Long64_t kElectronsPerTask = 4096;
3801 constexpr Long64_t kMinElectronsForParallel = 20000;
3803 struct AvalancheTask
3811 std::vector<AvalancheTask> aval_tasks;
3813 std::vector<Double_t> exact_x, exact_y;
3820 std::vector<std::thread> workers;
3823 std::condition_variable cv_start;
3824 std::condition_variable cv_done;
3825 const std::function<void(
size_t)>* job =
nullptr;
3827 std::atomic<size_t> next{0};
3828 size_t generation = 0;
3832 explicit ThreadPool(
size_t n_workers)
3834 workers.reserve(n_workers);
3835 for (
size_t i = 0;
i < n_workers; ++
i)
3836 workers.emplace_back([
this] { Loop(); });
3842 std::lock_guard<std::mutex> lk(mtx);
3845 cv_start.notify_all();
3846 for (
auto& w : workers)
3852 for (
size_t i = next.fetch_add(1);
i < n_items;
i = next.fetch_add(1))
3861 std::unique_lock<std::mutex> lk(mtx);
3862 cv_start.wait(lk, [&] {
return stop || generation != seen; });
3869 std::lock_guard<std::mutex> lk(mtx);
3871 cv_done.notify_one();
3877 void Run(
size_t n,
const std::function<
void(
size_t)>& func)
3881 if (workers.empty() ||
n == 1) {
3882 for (
size_t i = 0;
i <
n; ++
i)
3887 std::lock_guard<std::mutex> run_lock(run_mtx);
3889 std::lock_guard<std::mutex> lk(mtx);
3893 n_busy = workers.size();
3896 cv_start.notify_all();
3900 std::unique_lock<std::mutex> lk(mtx);
3901 cv_done.wait(lk, [&] {
return n_busy == 0; });
3907 static ThreadPool pool(std::max(1u, std::thread::hardware_concurrency()) - 1);
3909 auto parallel_for = [](
size_t n,
const std::function<void(
size_t)>& func) { pool.Run(
n, func); };
3912 if (!use_external_segs) {
3915 Double_t current_length_ratio = 0.0;
3919 std::vector<CollPoint> collision_points;
3925 while (current_length < track_length) {
3928 current_length += current_step;
3930 if (current_length > track_length)
3933 current_length_ratio = current_length / track_length;
3935 Double_t current_x = x + current_length_ratio * x_vec_from_in_to_out;
3936 Double_t current_y = y + current_length_ratio * y_vec_from_in_to_out;
3937 Double_t current_z = z + current_length_ratio * z_vec_from_in_to_out;
3939 collision_points.push_back(
CollPoint(current_x, current_y, current_z));
3944 for (
size_t icoll = 0; icoll < collision_points.size(); ++icoll) {
3946 Double_t xcoll = collision_points[icoll].x;
3947 Double_t ycoll = collision_points[icoll].y;
3948 Double_t zcoll = collision_points[icoll].z;
3961 xmean = p0_xmean + p1_xmean * zdist + p2_xmean * zdist * zdist + p3_xmean * zdist * zdist * zdist;
3962 sigma = p0_sigma + p1_sigma * zdist + p2_sigma * zdist * zdist + p3_sigma * zdist * zdist * zdist
3963 + p4_sigma * zdist * zdist * zdist * zdist + p5_sigma * zdist * zdist * zdist * zdist * zdist;
3966 Int_t n_electrons_cluster =
gRandom->Landau(1.027, 0.11);
3967 if (n_electrons_cluster < 1)
3968 n_electrons_cluster = 1;
3969 if (n_electrons_cluster > 6)
3970 n_electrons_cluster = 6;
3976 std::sqrt((xcoll - x) * (xcoll - x) + (ycoll - y) * (ycoll - y) + (zcoll - z) * (zcoll - z));
3978 dist_from_start = std::sqrt((xcoll - x_out) * (xcoll - x_out) + (ycoll - y_out) * (ycoll - y_out)
3979 + (zcoll - z_out) * (zcoll - z_out));
3981 Int_t segment = (
Int_t)(dist_from_start / track_length * n_track_segments);
3982 if (segment >= n_track_segments)
3983 segment = n_track_segments - 1;
3986 for (
Int_t ielectron = 0; ielectron < n_electrons_cluster; ++ielectron) {
3993 if (gain_gem1 < 1.0)
3995 if (gain_gem2 < 1.0)
3997 if (gain_gem3 < 1.0)
4002 if (zdist < level1) {
4005 if (zdist >= level1 && zdist < level2) {
4006 total_gain = gain_gem3;
4008 if (zdist >= level2 && zdist < level3) {
4009 total_gain = gain_gem3 * gain_gem2;
4011 if (zdist >= level3) {
4012 total_gain = gain_gem3 * gain_gem2 * gain_gem1;
4015 seg_local[segment] += total_gain;
4028 if (kExactGRandomSequence) {
4030 for (
int igain = 0; igain < total_gain; ++igain) {
4031 exact_x.push_back(
gRandom->Gaus(x_center, sigma));
4032 exact_y.push_back(
gRandom->Gaus(ycoll, sigma));
4036 for (
Long64_t done = 0; done < total_gain; done += kElectronsPerTask) {
4037 aval_tasks.push_back({x_center, ycoll, sigma, n_aval_electrons + done,
4038 std::min<Long64_t>(kElectronsPerTask, total_gain - done)});
4040 n_aval_electrons += total_gain;
4054 const size_t n_electrons = kExactGRandomSequence ? exact_x.size() :
static_cast<size_t>(n_aval_electrons);
4056 if (n_electrons > 0) {
4058 const Bool_t run_parallel =
static_cast<Long64_t>(n_electrons) >= kMinElectronsForParallel;
4059 const size_t chunk_size =
static_cast<size_t>(kElectronsPerTask);
4062 std::vector<char> layer_vertical(n_strip_layers);
4063 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer)
4069 std::vector<Int_t> lo;
4070 std::vector<std::vector<Int_t>> cnt;
4072 const size_t n_tasks =
4073 kExactGRandomSequence ? (n_electrons + chunk_size - 1) / chunk_size : aval_tasks.size();
4074 std::vector<TaskCounts> task_counts(n_tasks);
4077 auto count_electron = [&](TaskCounts& tc,
Double_t x_readout,
Double_t y_readout) {
4078 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
4082 if (!
StripLayers[ilayer].IsPointInsideStripLayer(x_readout, y_readout))
4085 Double_t strip_pos =
StripLayers[ilayer].ConvertPointToStripPosition(x_readout, y_readout);
4087 Double_t dstrip = strip_pos - (int)strip_pos;
4088 if (layer_vertical[ilayer]) {
4090 if (dstrip >= 0.4 && dstrip < 0.6)
4094 if (dstrip >= 0.3 && dstrip < 0.7)
4100 std::vector<Int_t>& cnt = tc.cnt[ilayer];
4101 Int_t& lo = tc.lo[ilayer];
4105 }
else if (strip < lo) {
4106 cnt.insert(cnt.begin(), lo - strip, 0);
4108 }
else if (strip >= lo +
static_cast<Int_t>(cnt.size())) {
4109 cnt.resize(strip - lo + 1, 0);
4115 auto init_counts = [&](TaskCounts& tc) {
4116 tc.lo.assign(n_strip_layers, 0);
4117 tc.cnt.assign(n_strip_layers, std::vector<Int_t>());
4120 if (kExactGRandomSequence) {
4122 auto process_chunk = [&](
size_t ichunk) {
4123 TaskCounts& tc = task_counts[ichunk];
4125 const size_t begin = ichunk * chunk_size;
4126 const size_t end = std::min(n_electrons, begin + chunk_size);
4127 for (
size_t ie = begin; ie < end; ++ie)
4128 count_electron(tc, exact_x[ie], exact_y[ie]);
4132 parallel_for(n_tasks, process_chunk);
4134 for (
size_t ichunk = 0; ichunk < n_tasks; ++ichunk)
4135 process_chunk(ichunk);
4147 const UInt_t base_seed =
static_cast<UInt_t
>(
gRandom->Integer(0xFFFFFFFFu));
4157 auto process_task = [&](
size_t itask) {
4158 const AvalancheTask& t = aval_tasks[itask];
4159 TaskCounts& tc = task_counts[itask];
4161 std::seed_seq seq{base_seed,
static_cast<UInt_t
>(itask)};
4162 std::mt19937_64 rng(seq);
4163 std::normal_distribution<Double_t> gaus(0.0, 1.0);
4166 const Double_t x_readout = t.xcenter + t.sigma * gaus(rng);
4167 const Double_t y_readout = t.ycenter + t.sigma * gaus(rng);
4170 const size_t ie = first_electron +
static_cast<size_t>(t.offset +
i);
4175 count_electron(tc, x_readout, y_readout);
4180 parallel_for(n_tasks, process_task);
4182 for (
size_t itask = 0; itask < n_tasks; ++itask)
4183 process_task(itask);
4188 auto fill_layer = [&](
size_t ilayer) {
4190 const Int_t n_strips_in_layer = std::max(0,
StripLayers[ilayer].GetNStrips());
4191 std::vector<Double_t> strip_acc(n_strips_in_layer, 0.0);
4192 Int_t acc_min = std::numeric_limits<Int_t>::max();
4195 for (
size_t itask = 0; itask < n_tasks; ++itask) {
4196 const Int_t lo = task_counts[itask].lo[ilayer];
4197 const std::vector<Int_t>& cnt = task_counts[itask].cnt[ilayer];
4198 for (
size_t i = 0;
i < cnt.size(); ++
i) {
4202 if (strip >= 0 && strip < n_strips_in_layer) {
4203 strip_acc[strip] += cnt[
i];
4204 if (strip < acc_min)
4206 if (strip > acc_max)
4215 for (
Int_t istrip = acc_min; istrip <= acc_max; ++istrip) {
4216 if (strip_acc[istrip] > 0.0)
4217 cluster.
AddStrip(istrip, strip_acc[istrip]);
4222 parallel_for(
static_cast<size_t>(n_strip_layers), fill_layer);
4224 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer)
4234 const vector<Int_t>& seg_used = use_external_segs ? segs : seg_local;
4250 drift_direction = 1;
4256 Double_t max_segment_val = *(std::max_element(seg_used.begin(), seg_used.end()));
4260 for (
size_t i = 0;
i < seg_used.size(); ++
i)
4261 total_charge += seg_used[
i];
4266 float common_input[n_common_inputs];
4267 common_input[0] =
static_cast<float>(px_norm);
4268 common_input[1] =
static_cast<float>(py_norm);
4269 common_input[2] =
static_cast<float>(pz_norm);
4270 common_input[3] =
static_cast<float>(drift_direction);
4271 common_input[4] =
static_cast<float>(bfield_used);
4272 for (
Int_t iseg = 0; iseg < n_segs_features; ++iseg)
4273 common_input[5 + iseg] =
4274 (max_segment_val > 0.0) ?
static_cast<float>(seg_used[iseg] / max_segment_val) : 0.0f;
4276 if (total_charge > 0.0) {
4278 const Int_t center_strip_index = n_ann_strips / 2;
4281 std::vector<Int_t> ann_layers;
4282 std::vector<Int_t> ann_center_strips;
4283 std::vector<Int_t> ann_n_strips;
4284 std::vector<float> ann_layer_inputs;
4285 ann_layers.reserve(n_strip_layers);
4286 ann_center_strips.reserve(n_strip_layers);
4287 ann_n_strips.reserve(n_strip_layers);
4288 ann_layer_inputs.reserve(n_strip_layers * n_layer_inputs);
4290 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
4293 if (!
StripLayers[ilayer].IsPointInsideStripLayer(x_c, y_c))
4297 if (n_strips_in_layer <= 0)
4303 Double_t center_frac = center_pos - center_strip;
4309 ann_layers.push_back(ilayer);
4310 ann_center_strips.push_back(center_strip);
4311 ann_n_strips.push_back(n_strips_in_layer);
4312 ann_layer_inputs.push_back(
static_cast<float>(strip_layer));
4313 ann_layer_inputs.push_back(
static_cast<float>(strip_order));
4314 ann_layer_inputs.push_back(
static_cast<float>(center_frac));
4318 Int_t n_ann_layers = ann_layers.size();
4319 std::vector<float> ann_strip_values(
static_cast<size_t>(n_ann_layers) * n_ann_strips);
4320 if (n_ann_layers > 0
4321 && !mlp_model->
PredictSplit(common_input, n_common_inputs, ann_layer_inputs.data(), n_ann_layers,
4322 ann_strip_values.data()))
4324 LOG(error) <<
"BmnGemStripModule::" << __func__ <<
"(): MLP prediction failed";
4328 for (
Int_t iann = 0; iann < n_ann_layers; ++iann) {
4329 const Int_t ilayer = ann_layers[iann];
4330 const Int_t center_strip = ann_center_strips[iann];
4331 const Int_t n_strips_in_layer = ann_n_strips[iann];
4332 const float* strip_values = ann_strip_values.data() +
static_cast<size_t>(iann) * n_ann_strips;
4336 for (
Int_t istrip = 0; istrip < n_ann_strips; ++istrip)
4337 sum_norm += strip_values[istrip];
4340 const Double_t ann_correction_lower = 0.8;
4341 const Double_t ann_correction_upper = 0.6;
4347 signal_scale = (total_charge / sum_norm) * ann_correction;
4349 Double_t threshold = 0.0001 * total_charge;
4352 for (
Int_t istrip = 0; istrip < n_ann_strips; ++istrip) {
4353 Double_t content = strip_values[istrip] * signal_scale;
4354 if (content <= threshold)
4357 Int_t strip_num = center_strip - center_strip_index + istrip;
4358 if (strip_num < 0 || strip_num >= n_strips_in_layer)
4361 cluster_layers[ilayer].AddStrip(strip_num, content);
4371 if (use_external_segs)
4379 vector<Double_t> cluster_mean_position(n_strip_layers, 0.0);
4380 vector<Double_t> cluster_total_signal(n_strip_layers, 0.0);
4382 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
4384 if (cluster_layers[ilayer].GetClusterSize() > 0) {
4386 for (
int i = 0;
i < cluster_layers[ilayer].GetClusterSize(); ++
i) {
4387 cluster_mean_position[ilayer] += (cluster_layers[ilayer].Strips[
i] + 0.5)
4388 * cluster_layers[ilayer].Signals[
i];
4389 cluster_total_signal[ilayer] += cluster_layers[ilayer].Signals[
i];
4391 cluster_mean_position[ilayer] /= cluster_total_signal[ilayer];
4394 cluster_layers[ilayer].MeanPosition = cluster_mean_position[ilayer];
4395 cluster_layers[ilayer].TotalSignal = cluster_total_signal[ilayer];
4400 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
4401 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x, y);
4404 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
4405 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x_out, y_out);
4410 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
4411 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x_out, y_out);
4414 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
4415 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x, y);
4420 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
4421 cluster_layers[ilayer].PositionResidual =
4422 cluster_layers[ilayer].MeanPosition - cluster_layers[ilayer].OriginPosition;
4423 cluster_layers[ilayer].SetType(
StripLayers[ilayer].GetType());
4430 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
4435 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
4442 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
4443 for (
size_t ielement = 0; ielement < cluster_layers[ilayer].Strips.size(); ++ielement) {
4444 Int_t strip_num = cluster_layers[ilayer].Strips.at(ielement);
4445 Double_t strip_signal = cluster_layers[ilayer].Signals.at(ielement);
4446 StripLayers[ilayer].AddStripSignal(strip_num, strip_signal);
4452 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
4453 for (
size_t ielement = 0; ielement < cluster_layers[ilayer].Strips.size(); ++ielement) {
4454 Int_t strip_num = cluster_layers[ilayer].Strips.at(ielement);
4455 Double_t strip_signal = cluster_layers[ilayer].Signals.at(ielement);
4456 StripLayers[ilayer].AddLinkToStripMatch(strip_num, strip_signal / cluster_layers[ilayer].TotalSignal,
4503 const Int_t n_track_segments = 64;
4504 const Int_t n_segs_features = n_track_segments;
4505 const Int_t n_common_inputs = 5 + n_segs_features;
4506 const Int_t n_layer_inputs = 3;
4507 Int_t n_ann_strips = 0;
4513 std::shared_ptr<const BmnGemStripMLPModel> mlp_holder;
4515 if (!onlyStandard) {
4517 mlp_model = mlp_holder.get();
4519 static std::mutex checked_mutex;
4520 static std::map<const BmnGemStripMLPModel*, std::pair<std::shared_ptr<const BmnGemStripMLPModel>, std::string>>
4523 std::lock_guard<std::mutex> lock(checked_mutex);
4525 LOG(warn) <<
"BmnGemStripModule::" << __func__
4526 <<
"(): MLP model is not available, the standard method is used";
4528 auto it = checked.find(mlp_model);
4529 if (it == checked.end()) {
4530 std::vector<std::string> expected = {
"px",
"py",
"pz",
"drift",
"bfield"};
4531 for (
Int_t iseg = 0; iseg < n_segs_features; ++iseg)
4532 expected.push_back(
"s" + std::to_string(iseg));
4533 expected.insert(expected.end(), {
"strip_layer",
"strip_order",
"center_frac"});
4543 LOG(info) <<
"BmnGemStripModule::" << __func__ <<
"(): MLP model " << mlp_model->
GetFilePath()
4544 <<
" is used (ANN for |theta| < " << maxThetaAngle <<
" deg, window "
4546 }
else if (why.empty())
4547 why =
"unknown reason";
4548 it = checked.emplace(mlp_model, std::make_pair(mlp_holder, why)).first;
4550 if (!it->second.second.empty()) {
4551 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): the model " << mlp_model->
GetFilePath()
4552 <<
" is not suitable (" << it->second.second <<
"), the standard method is used";
4553 mlp_model =
nullptr;
4563 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): Point (" << x <<
" : " << y <<
" : " << z
4564 <<
") is out of the readout plane or inside a dead zone";
4569 Int_t pdg = pdg_code;
4577 if (points && mctracks && refID >= 0 && refID < points->GetEntriesFast()) {
4579 if (point && point->GetTrackID() >= 0 && point->GetTrackID() < mctracks->
GetEntriesFast())
4586 static std::atomic<bool> no_mc_reported{
false};
4587 if (!no_mc_reported.exchange(
true))
4588 LOG(warn) <<
"BmnGemStripModule::" << __func__
4589 <<
"(): pdg_code = 0 and the MC track is not available (no GemDigitizer or MC point), "
4590 "the He4 mass is used (this warning is printed once)";
4597 Double_t mnoc = 1.0, mass = 3.7283999;
4599 mass = part->
Mass();
4600 if (mass > 0.0001) {
4615 Double_t z_distance_from_in_to_out;
4625 if (z_distance_from_in_to_out <= 0.0) {
4626 LOG(warn) <<
"BmnGemStripModule::" << __func__ <<
"(): Point (" << x <<
" : " << y <<
" : " << z
4627 <<
") has a track with an incorrect length";
4632 Double_t vector_coeff =
fabs(z_distance_from_in_to_out / pz);
4635 Double_t x_vec_from_in_to_out = vector_coeff * px;
4636 Double_t y_vec_from_in_to_out = vector_coeff * py;
4637 Double_t z_vec_from_in_to_out = vector_coeff * pz;
4640 Double_t x_out = x + x_vec_from_in_to_out;
4641 Double_t y_out = y + y_vec_from_in_to_out;
4642 Double_t z_out = z + z_vec_from_in_to_out;
4646 if (x_out < XMinModule || x_out >
XMaxModule) {
4652 x_vec_from_in_to_out = x_out - x;
4653 vector_coeff = x_vec_from_in_to_out / px;
4655 y_vec_from_in_to_out = vector_coeff * py;
4656 z_vec_from_in_to_out = vector_coeff * pz;
4658 y_out = y + y_vec_from_in_to_out;
4659 z_out = z + z_vec_from_in_to_out;
4662 if (y_out < YMinModule || y_out >
YMaxModule) {
4668 y_vec_from_in_to_out = y_out - y;
4669 vector_coeff = y_vec_from_in_to_out / py;
4671 x_vec_from_in_to_out = vector_coeff * px;
4672 z_vec_from_in_to_out = vector_coeff * pz;
4674 x_out = x + x_vec_from_in_to_out;
4675 z_out = z + z_vec_from_in_to_out;
4686 std::sqrt((x_vec_from_in_to_out) * (x_vec_from_in_to_out) + (y_vec_from_in_to_out) * (y_vec_from_in_to_out)
4687 + (z_vec_from_in_to_out) * (z_vec_from_in_to_out));
4693 const Bool_t useANN = (theta_deg_abs < maxThetaAngle) && mlp_model;
4696 const Bool_t use_external_segs = useANN && !segs.empty();
4697 if (use_external_segs && segs.size() <
static_cast<size_t>(n_segs_features)) {
4698 LOG(error) <<
"BmnGemStripModule::" << __func__ <<
"(): segment vector size = " << segs.size()
4699 <<
", the model requires " << n_segs_features;
4730 vector<StripCluster> cluster_layers(n_strip_layers,
StripCluster());
4733 vector<Int_t> seg_local(n_track_segments, 0);
4738 struct CollisionTask
4745 std::vector<CollisionTask> coll_tasks;
4748 if (!use_external_segs) {
4751 Double_t current_length_ratio = 0.0;
4755 std::vector<CollPoint> collision_points;
4761 while (current_length < track_length) {
4764 current_length += current_step;
4766 if (current_length > track_length)
4769 current_length_ratio = current_length / track_length;
4771 Double_t current_x = x + current_length_ratio * x_vec_from_in_to_out;
4772 Double_t current_y = y + current_length_ratio * y_vec_from_in_to_out;
4773 Double_t current_z = z + current_length_ratio * z_vec_from_in_to_out;
4775 collision_points.push_back(
CollPoint(current_x, current_y, current_z));
4780 for (
size_t icoll = 0; icoll < collision_points.size(); ++icoll) {
4782 Double_t xcoll = collision_points[icoll].x;
4783 Double_t ycoll = collision_points[icoll].y;
4784 Double_t zcoll = collision_points[icoll].z;
4797 xmean = p0_xmean + p1_xmean * zdist + p2_xmean * zdist * zdist + p3_xmean * zdist * zdist * zdist;
4798 sigma = p0_sigma + p1_sigma * zdist + p2_sigma * zdist * zdist + p3_sigma * zdist * zdist * zdist
4799 + p4_sigma * zdist * zdist * zdist * zdist + p5_sigma * zdist * zdist * zdist * zdist * zdist;
4802 Int_t n_electrons_cluster =
gRandom->Landau(1.027, 0.11);
4803 if (n_electrons_cluster < 1)
4804 n_electrons_cluster = 1;
4805 if (n_electrons_cluster > 6)
4806 n_electrons_cluster = 6;
4812 std::sqrt((xcoll - x) * (xcoll - x) + (ycoll - y) * (ycoll - y) + (zcoll - z) * (zcoll - z));
4814 dist_from_start = std::sqrt((xcoll - x_out) * (xcoll - x_out) + (ycoll - y_out) * (ycoll - y_out)
4815 + (zcoll - z_out) * (zcoll - z_out));
4817 Int_t segment = (
Int_t)(dist_from_start / track_length * n_track_segments);
4818 if (segment >= n_track_segments)
4819 segment = n_track_segments - 1;
4824 for (
Int_t ielectron = 0; ielectron < n_electrons_cluster; ++ielectron) {
4831 if (gain_gem1 < 1.0)
4833 if (gain_gem2 < 1.0)
4835 if (gain_gem3 < 1.0)
4840 if (zdist < level1) {
4843 if (zdist >= level1 && zdist < level2) {
4844 total_gain = gain_gem3;
4846 if (zdist >= level2 && zdist < level3) {
4847 total_gain = gain_gem3 * gain_gem2;
4849 if (zdist >= level3) {
4850 total_gain = gain_gem3 * gain_gem2 * gain_gem1;
4853 seg_local[segment] += total_gain;
4860 coll_electrons += total_gain;
4864 if (!useANN && coll_electrons > 0) {
4867 coll_tasks.push_back({x_center, ycoll, sigma, coll_electrons});
4882 if (!useANN && !coll_tasks.empty()) {
4887 std::mt19937_64 rng(
static_cast<UInt_t
>(
gRandom->Integer(0xFFFFFFFFu)));
4888 std::normal_distribution<Double_t> gaus01(0.0, 1.0);
4889 std::binomial_distribution<Long64_t> binom;
4890 using BinomParam = std::binomial_distribution<Long64_t>::param_type;
4903 std::vector<Double_t> acc;
4904 Int_t acc_min = std::numeric_limits<Int_t>::max(), acc_max = -1;
4906 std::vector<LayerSetup> ls(n_strip_layers);
4908 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
4909 LayerSetup& s = ls[ilayer];
4915 s.n_strips = std::max(0, layer.
GetNStrips());
4916 s.acc.assign(s.n_strips, 0.0);
4924 s.a = (u10 - u00) / h;
4925 s.b = (u01 - u00) / h;
4928 s.linear = std::isfinite(s.grad) &&
TMath::Abs(u11 - u10 - u01 + u00) <= 1e-9 * (1.0 +
TMath::Abs(u00));
4937 const Double_t dstrip = strip_pos - (int)strip_pos;
4938 if (dstrip >= ls[ilayer].d1 && dstrip < ls[ilayer].d2)
4941 LayerSetup& s = ls[ilayer];
4942 if (strip >= 0 && strip < s.n_strips) {
4943 s.acc[strip] += 1.0;
4944 s.acc_min = std::min(s.acc_min, strip);
4945 s.acc_max = std::max(s.acc_max, strip);
4947 cluster_layers[ilayer].AddStrip(strip, 1.0);
4953 LayerSetup& s = ls[ilayer];
4954 if (strip >= 0 && strip < s.n_strips) {
4955 s.acc[strip] +=
static_cast<Double_t>(
n);
4956 s.acc_min = std::min(s.acc_min, strip);
4957 s.acc_max = std::max(s.acc_max, strip);
4959 cluster_layers[ilayer].AddStrip(strip,
static_cast<Double_t>(
n));
4963 for (
const CollisionTask& t : coll_tasks) {
4964 const Double_t box = kNSigma * t.sigma;
4966 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
4967 LayerSetup& s = ls[ilayer];
4981 const Double_t sigma_u = t.sigma * s.grad;
4982 const Double_t u_lo = u0 - kNSigma * sigma_u;
4983 const Double_t u_hi = u0 + kNSigma * sigma_u;
4985 const Bool_t analytic = s.linear && n_inside == 5 && u_lo >= 0.0 && sigma_u > 1e-12;
4989 for (
Long64_t ie = 0; ie < t.n; ++ie) {
4990 const Double_t x_readout = t.xcenter + t.sigma * gaus01(rng);
4991 const Double_t y_readout = t.ycenter + t.sigma * gaus01(rng);
4992 add_electron(ilayer, x_readout, y_readout);
5003 for (
Int_t j = j_lo; j <= j_hi && n_left > 0; ++j) {
5004 const Double_t p = (Phi((j + s.d1 - u0) / sigma_u) - Phi((j - u0) / sigma_u))
5005 + (Phi((j + 1 - u0) / sigma_u) - Phi((j + s.d2 - u0) / sigma_u));
5008 if (mass_left <= 0.0)
5013 const Long64_t k = binom(rng, BinomParam(n_left, q));
5015 add_strip(ilayer, j, k);
5024 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5025 const LayerSetup& s = ls[ilayer];
5026 for (
Int_t istrip = s.acc_min; istrip <= s.acc_max; ++istrip) {
5027 if (s.acc[istrip] > 0.0)
5028 cluster_layers[ilayer].AddStrip(istrip, s.acc[istrip]);
5038 const vector<Int_t>& seg_used = use_external_segs ? segs : seg_local;
5054 drift_direction = 1;
5060 Double_t max_segment_val = *(std::max_element(seg_used.begin(), seg_used.end()));
5064 for (
size_t i = 0;
i < seg_used.size(); ++
i)
5065 total_charge += seg_used[
i];
5070 float common_input[n_common_inputs];
5071 common_input[0] =
static_cast<float>(px_norm);
5072 common_input[1] =
static_cast<float>(py_norm);
5073 common_input[2] =
static_cast<float>(pz_norm);
5074 common_input[3] =
static_cast<float>(drift_direction);
5075 common_input[4] =
static_cast<float>(bfield_used);
5076 for (
Int_t iseg = 0; iseg < n_segs_features; ++iseg)
5077 common_input[5 + iseg] =
5078 (max_segment_val > 0.0) ?
static_cast<float>(seg_used[iseg] / max_segment_val) : 0.0f;
5080 if (total_charge > 0.0) {
5082 const Int_t center_strip_index = n_ann_strips / 2;
5085 std::vector<Int_t> ann_layers;
5086 std::vector<Int_t> ann_center_strips;
5087 std::vector<Int_t> ann_n_strips;
5088 std::vector<float> ann_layer_inputs;
5089 ann_layers.reserve(n_strip_layers);
5090 ann_center_strips.reserve(n_strip_layers);
5091 ann_n_strips.reserve(n_strip_layers);
5092 ann_layer_inputs.reserve(n_strip_layers * n_layer_inputs);
5094 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5097 if (!
StripLayers[ilayer].IsPointInsideStripLayer(x_c, y_c))
5101 if (n_strips_in_layer <= 0)
5107 Double_t center_frac = center_pos - center_strip;
5113 ann_layers.push_back(ilayer);
5114 ann_center_strips.push_back(center_strip);
5115 ann_n_strips.push_back(n_strips_in_layer);
5116 ann_layer_inputs.push_back(
static_cast<float>(strip_layer));
5117 ann_layer_inputs.push_back(
static_cast<float>(strip_order));
5118 ann_layer_inputs.push_back(
static_cast<float>(center_frac));
5122 Int_t n_ann_layers = ann_layers.size();
5123 std::vector<float> ann_strip_values(
static_cast<size_t>(n_ann_layers) * n_ann_strips);
5124 if (n_ann_layers > 0
5125 && !mlp_model->
PredictSplit(common_input, n_common_inputs, ann_layer_inputs.data(), n_ann_layers,
5126 ann_strip_values.data()))
5128 LOG(error) <<
"BmnGemStripModule::" << __func__ <<
"(): MLP prediction failed";
5132 for (
Int_t iann = 0; iann < n_ann_layers; ++iann) {
5133 const Int_t ilayer = ann_layers[iann];
5134 const Int_t center_strip = ann_center_strips[iann];
5135 const Int_t n_strips_in_layer = ann_n_strips[iann];
5136 const float* strip_values = ann_strip_values.data() +
static_cast<size_t>(iann) * n_ann_strips;
5140 for (
Int_t istrip = 0; istrip < n_ann_strips; ++istrip)
5141 sum_norm += strip_values[istrip];
5144 const Double_t ann_correction_lower = 0.8;
5145 const Double_t ann_correction_upper = 0.6;
5151 signal_scale = (total_charge / sum_norm) * ann_correction;
5153 Double_t threshold = 0.0001 * total_charge;
5156 for (
Int_t istrip = 0; istrip < n_ann_strips; ++istrip) {
5157 Double_t content = strip_values[istrip] * signal_scale;
5158 if (content <= threshold)
5161 Int_t strip_num = center_strip - center_strip_index + istrip;
5162 if (strip_num < 0 || strip_num >= n_strips_in_layer)
5165 cluster_layers[ilayer].AddStrip(strip_num, content);
5175 if (use_external_segs)
5183 vector<Double_t> cluster_mean_position(n_strip_layers, 0.0);
5184 vector<Double_t> cluster_total_signal(n_strip_layers, 0.0);
5186 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5188 if (cluster_layers[ilayer].GetClusterSize() > 0) {
5190 for (
int i = 0;
i < cluster_layers[ilayer].GetClusterSize(); ++
i) {
5191 cluster_mean_position[ilayer] += (cluster_layers[ilayer].Strips[
i] + 0.5)
5192 * cluster_layers[ilayer].Signals[
i];
5193 cluster_total_signal[ilayer] += cluster_layers[ilayer].Signals[
i];
5195 cluster_mean_position[ilayer] /= cluster_total_signal[ilayer];
5198 cluster_layers[ilayer].MeanPosition = cluster_mean_position[ilayer];
5199 cluster_layers[ilayer].TotalSignal = cluster_total_signal[ilayer];
5204 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5205 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x, y);
5208 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5209 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x_out, y_out);
5214 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5215 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x_out, y_out);
5218 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5219 cluster_layers[ilayer].OriginPosition =
StripLayers[ilayer].ConvertPointToStripPosition(x, y);
5224 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5225 cluster_layers[ilayer].PositionResidual =
5226 cluster_layers[ilayer].MeanPosition - cluster_layers[ilayer].OriginPosition;
5227 cluster_layers[ilayer].SetType(
StripLayers[ilayer].GetType());
5234 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5239 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5246 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5247 for (
size_t ielement = 0; ielement < cluster_layers[ilayer].Strips.size(); ++ielement) {
5248 Int_t strip_num = cluster_layers[ilayer].Strips.at(ielement);
5249 Double_t strip_signal = cluster_layers[ilayer].Signals.at(ielement);
5250 StripLayers[ilayer].AddStripSignal(strip_num, strip_signal);
5256 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5257 for (
size_t ielement = 0; ielement < cluster_layers[ilayer].Strips.size(); ++ielement) {
5258 Int_t strip_num = cluster_layers[ilayer].Strips.at(ielement);
5259 Double_t strip_signal = cluster_layers[ilayer].Signals.at(ielement);
5260 StripLayers[ilayer].AddLinkToStripMatch(strip_num, strip_signal / cluster_layers[ilayer].TotalSignal,
5706 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5711 map<Int_t, Bool_t> UsageStatus_LowerClusters;
5712 map<Int_t, Bool_t> UsageStatus_UpperClusters;
5715 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5716 for (
Int_t i_strip_hit = 0; i_strip_hit <
StripLayers[ilayer].GetNStripHits(); ++i_strip_hit) {
5719 UsageStatus_LowerClusters[cluster.
GetUniqueID()] =
false;
5722 UsageStatus_UpperClusters[cluster.
GetUniqueID()] =
false;
5727 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5728 for (
Int_t jlayer = ilayer + 1; jlayer < n_strip_layers; ++jlayer) {
5737 if (
Abs(iAngleRad - jAngleRad) < 0.01)
5743 for (
Int_t i_strip_hit = 0; i_strip_hit <
StripLayers[ilayer].GetNStripHits(); ++i_strip_hit) {
5744 for (
Int_t j_strip_hit = 0; j_strip_hit <
StripLayers[jlayer].GetNStripHits(); ++j_strip_hit) {
5755 if (
Abs(iAngleRad) >= 0.01 &&
Abs(jAngleRad) >= 0.01) {
5760 xcoord = (jB - iB) / (
Tan(i_PiOver2MinusAngleRad) -
Tan(j_PiOver2MinusAngleRad));
5761 ycoord =
Tan(i_PiOver2MinusAngleRad) * xcoord + iB;
5764 if (
Abs(iAngleRad) < 0.01) {
5767 xcoord =
StripLayers[ilayer].GetXLeftStripBorderPoint()
5770 xcoord =
StripLayers[ilayer].GetXRightStripBorderPoint()
5775 ycoord =
Tan(j_PiOver2MinusAngleRad) * xcoord + jB;
5778 if (
Abs(jAngleRad) < 0.01) {
5781 xcoord =
StripLayers[jlayer].GetXLeftStripBorderPoint()
5784 xcoord =
StripLayers[jlayer].GetXRightStripBorderPoint()
5789 ycoord =
Tan(i_PiOver2MinusAngleRad) * xcoord + iB;
5794 if (
StripLayers[ilayer].IsPointInsideStripLayer(xcoord, ycoord)
5795 &&
StripLayers[jlayer].IsPointInsideStripLayer(xcoord, ycoord))
5802 Double_t AngleIntersecRad =
Abs(iAngleRad - jAngleRad);
5811 Double_t xcoord_err = xerr1 + xerr2;
5816 Double_t ycoord_err = yerr1 + yerr2;
5827 intersection_match.
AddLink(iStripMatch);
5828 intersection_match.
AddLink(jStripMatch);
5839 BmnMatch intersection_digit_num_match;
5840 intersection_digit_num_match.
AddLink(iStripDigitNumberMatch);
5841 intersection_digit_num_match.
AddLink(jStripDigitNumberMatch);
5848 Int_t iLayerClusterSize =
StripLayers[ilayer].GetStripHitClusterSize(i_strip_hit);
5849 Int_t jLayerClusterSize =
StripLayers[jlayer].GetStripHitClusterSize(j_strip_hit);
5852 Double_t iLayerStripPosition =
StripLayers[ilayer].ConvertPointToStripPosition(xcoord, ycoord);
5853 Double_t jLayerStripPosition =
StripLayers[jlayer].ConvertPointToStripPosition(xcoord, ycoord);
5861 StripLayers[ilayer].GetStripHitTotalSignal(i_strip_hit));
5863 StripLayers[jlayer].GetStripHitTotalSignal(j_strip_hit));
5866 UsageStatus_LowerClusters
5867 [
StripLayers[ilayer].GetStripClusters()[i_strip_hit].GetUniqueID()] =
true;
5868 UsageStatus_UpperClusters
5869 [
StripLayers[jlayer].GetStripClusters()[j_strip_hit].GetUniqueID()] =
true;
5876 StripLayers[jlayer].GetStripHitTotalSignal(j_strip_hit));
5878 StripLayers[ilayer].GetStripHitTotalSignal(i_strip_hit));
5881 UsageStatus_LowerClusters
5882 [
StripLayers[jlayer].GetStripClusters()[j_strip_hit].GetUniqueID()] =
true;
5883 UsageStatus_UpperClusters
5884 [
StripLayers[ilayer].GetStripClusters()[i_strip_hit].GetUniqueID()] =
true;
5897 for (
auto it : UsageStatus_LowerClusters) {
5901 if (it.second ==
false) {
5903 for (
Int_t ilayer = 0; ilayer < n_strip_layers; ++ilayer) {
5908 for (
size_t icluster = 0; icluster <
StripLayers[ilayer].GetStripClusters().size(); ++icluster) {
5918 xcoord =
StripLayers[ilayer].GetXLeftStripBorderPoint()
5921 xcoord =
StripLayers[ilayer].GetXRightStripBorderPoint()
5949 StripLayers[ilayer].ConvertPointToStripPosition(xcoord, ycoord));