1#include "TrigScint/TrigScintTrackProducer.h"
12 "seeding_collection");
13 input_collections_ = ps.
getParameter<std::vector<std::string>>(
14 "further_input_collections");
16 output_collection_ = ps.
getParameter<std::string>(
"output_collection");
17 passName_ = ps.
getParameter<std::string>(
"input_pass_name");
19 vertBarStartIdx_ = ps.
getParameter<
int>(
"vertical_bar_start_index");
20 nBarsY_ = ps.
getParameter<
int>(
"number_horizontal_bars");
21 barWidth_y_ = ps.
getParameter<
double>(
"horizontal_bar_width");
22 barGap_y_ = ps.
getParameter<
double>(
"horizontal_bar_gap");
24 barWidth_x_ = ps.
getParameter<
double>(
"vertical_bar_width");
26 skipLast_ = ps.
getParameter<
bool>(
"allow_skip_last_collection");
31 ldmx_log(info) <<
"In TrigScintTrackProducer: configure done!" << std::endl;
32 ldmx_log(info) <<
"Got parameters: \nSeeding: " << seeding_collection_
33 <<
"\nTolerance: " << maxDelta_
34 <<
"\nInput: " << input_collections_.at(0) <<
" and "
35 << input_collections_.at(1)
36 <<
"\nInput pass name: " << passName_
37 <<
"\nAllow tracks with no hit in last collection: "
39 <<
"\nVertical bar start index: " << vertBarStartIdx_
40 <<
"\nNumber of horizontal bars: " << nBarsY_
41 <<
"\nHorizontal bar width: " << barWidth_y_
42 <<
"\nHorizontal bar gap: " << barGap_y_
43 <<
"\nNumber of vertical bars: " << nBarsX_
44 <<
"\nVertical bar width: " << barWidth_x_
45 <<
"\nVertical bar gap: " << barGap_x_
46 <<
"\nOutput: " << output_collection_
47 <<
"\nVerbosity: " << verbose_;
51 (barWidth_y_ + barGap_y_) /
53 yStart_ = -(nBarsY_ * (barWidth_y_ + barGap_y_) - barGap_y_) /
58 xStart_ = -(nBarsX_ * (barWidth_x_ + barGap_x_) - barGap_x_) /
74 <<
"TrigScintTrackProducer: produce() starts! Event number: "
75 <<
event.getEventHeader().getEventNumber();
77 if (!event.
exists(seeding_collection_, passName_)) {
78 ldmx_log(info) <<
"No collection called " << seeding_collection_
79 <<
"; skipping event";
84 if (!event.
exists(seeding_collection_, passName_)) {
85 ldmx_log(info) <<
"No collection called " << seeding_collection_
86 <<
"; skipping event";
90 seeding_collection_, passName_)};
91 uint numSeeds = seeds.size();
94 ldmx_log(debug) <<
"Got track seeding cluster collection "
95 << seeding_collection_ <<
" with " << numSeeds
99 if (!event.
exists(input_collections_.at(0), passName_)) {
100 ldmx_log(info) <<
"No collection called " << input_collections_.at(0)
101 <<
"; skipping event";
107 input_collections_.at(0), passName_)};
109 if (!event.
exists(input_collections_.at(1), passName_)) {
110 ldmx_log(info) <<
"No collection called "
111 << input_collections_.at(1)
113 <<
"; skipping event";
114 std::vector<ldmx::TrigScintTrack> empty{};
115 event.add(output_collection_, empty);
120 input_collections_.at(1), passName_)};
123 ldmx_log(debug) <<
"Got the other two pad collections:"
124 << input_collections_.at(0) <<
" with "
125 << clusters_pad1.size() <<
" entries, and "
126 << input_collections_.at(1) <<
" with "
127 << clusters_pad2.size() <<
" entries.";
130 std::vector<ldmx::TrigScintTrack> cleanedTracks;
131 std::vector<ldmx::TrigScintTrack> cleanedTracksY;
132 std::vector<ldmx::TrigScintTrack> cleanedTracksX;
137 if (numSeeds && clusters_pad1.size()) {
142 for (
const auto &seed : seeds) {
145 float centroid = seed.getCentroid();
147 std::vector<ldmx::TrigScintTrack> trackCandidates;
150 ldmx_log(debug) <<
"Got seed with centroid " << centroid;
156 for (
const auto &cluster1 : clusters_pad1) {
158 ldmx_log(debug) <<
"\tGot pad1 cluster with centroid "
159 << cluster1.getCentroid();
161 if (fabs(cluster1.getCentroid() - centroid) < maxDelta_ ||
162 (centroid >= vertBarStartIdx_
163 && seed.getCentroidX() == cluster1.getCentroidX())) {
167 if (centroid >= vertBarStartIdx_ &&
168 seed.getCentroidY() < cluster1.getCentroidY()) {
171 ldmx_log(debug) <<
"\tSkipping impossible x cluster combination "
172 "with y flags (tag up) ("
173 << seed.getCentroidY() <<
" "
174 << cluster1.getCentroidY() <<
")";
182 ldmx_log(debug) <<
"\t\tIt is close enough!. Check pad2";
187 std::vector<ldmx::TrigScintCluster> clusterVec = {seed, cluster1};
189 bool hasMatchDn =
false;
191 for (
const auto &cluster2 : clusters_pad2) {
193 ldmx_log(debug) <<
"\tGot pad2 cluster with centroid "
194 << cluster2.getCentroid();
197 if (fabs(cluster2.getCentroid() - centroid) < maxDelta_ ||
198 (centroid >= vertBarStartIdx_
199 && seed.getCentroidX() == cluster2.getCentroidX())) {
203 if (centroid >= vertBarStartIdx_ &&
204 (seed.getCentroidY() < cluster2.getCentroidY() ||
205 cluster1.getCentroidY() >
206 cluster2.getCentroidY())) {
209 <<
"\tSkipping impossible x cluster combination with y "
210 "flags (tag up dn) ("
211 << seed.getCentroidY() <<
" " << cluster1.getCentroidY()
212 <<
" " << cluster2.getCentroidY() <<
")";
220 ldmx_log(debug) <<
"\t\tIt is close enough!. Make a track";
225 std::vector<ldmx::TrigScintCluster> threeClusterVec = {
226 seed, cluster1, cluster2};
235 trackCandidates.push_back(track);
244 trackCandidates.push_back(track);
257 if (trackCandidates.size() == 0)
continue;
260 float minResidual = 1000;
263 if (trackCandidates.size() > 1) {
267 ldmx_log(debug) <<
"Got " << trackCandidates.size()
268 <<
" tracks to check.";
271 for (uint idx = 0; idx < trackCandidates.size(); idx++) {
272 if ((trackCandidates.at(idx)).getResidual() < minResidual) {
275 (trackCandidates.at(idx)).getResidual();
279 <<
"Track at index " << idx
280 <<
" has smallest residual so far: " << minResidual;
290 tracks_.push_back(trackCandidates.at(keepIdx));
292 ldmx_log(debug) <<
"Kept track at index " << keepIdx;
293 (trackCandidates.at(keepIdx)).Print();
299 if (tracks_.size() == 0) {
301 ldmx_log(debug) <<
"No tracks found!";
303 std::vector<ldmx::TrigScintTrack> empty{};
304 event.add(output_collection_, empty);
315 std::vector keepIndices(tracks_.size(), 1);
317 ldmx_log(debug) <<
"vector of indices to keep has size "
318 << keepIndices.size();
320 for (uint idx = tracks_.size() - 1; idx > 0; idx--) {
324 for (
int idxComp = idx - 1; idxComp >= 0; idxComp--) {
326 ldmx_log(debug) <<
"In track disambiguation loop, idx points at "
327 << idx <<
" and prev idx points at " << idxComp;
335 std::vector<ldmx::TrigScintCluster> consts_1 =
337 std::vector<ldmx::TrigScintCluster> consts_2 =
341 <<
"In track disambiguation loop, got the two tracks, "
342 "with nConstituents "
343 << consts_1.size() <<
" and " << consts_2.size()
344 <<
", respectively. ";
347 if (consts_1[1].getCentroid() == consts_2[1].getCentroid() ||
348 (consts_1.size() > 2 && consts_2.size() > 2 &&
349 consts_1[2].getCentroid() ==
356 ldmx_log(debug) <<
"Found overlap! Tracks at index " << idx
357 <<
" and " << idxComp;
358 (tracks_.at(idx)).Print();
359 (tracks_.at(idxComp)).Print();
362 if ((tracks_.at(idx)).getResidual() <
363 (tracks_.at(idxComp)).getResidual()) {
366 keepIndices.at(idxComp) = 0;
370 keepIndices.at(idx) = 0;
388 for (uint idx = 0; idx < tracks_.size(); idx++) {
390 ldmx_log(debug) <<
"keep flag for idx " << idx <<
" is "
391 << keepIndices.at(idx);
393 if (keepIndices.at(idx)) {
395 cleanedTracks.push_back(tracks_.at(idx));
398 ldmx_log(debug) <<
"After cleaning, keeping track at index " << idx
399 <<
": Centroid = " << (tracks_.at(idx)).getCentroid()
401 << (tracks_.at(idx)).getCentroidX()
403 << (tracks_.at(idx)).getCentroidY()
404 <<
"; track PE = " << (tracks_.at(idx)).getPE();
419 ldmx_log(debug) <<
"Running track x,y matching ";
422 if (cleanedTracks.size() > 0) {
423 matchXYTracks(cleanedTracks);
424 std::vector<ldmx::TrigScintTrack> matchedTracks =
430 for (
auto trk : matchedTracks) {
441 if (trk.getCentroid() >= vertBarStartIdx_)
442 cleanedTracksX.push_back(trk);
444 cleanedTracksY.push_back(trk);
447 float centr = trk.getCentroid();
448 std::string collStr = centr >= vertBarStartIdx_ ?
"X" :
"Y";
449 collStr = output_collection_ + collStr;
450 ldmx_log(debug) <<
"saving track with centroid " << centr
451 <<
" to output track collection " << collStr;
460 <<
"Not all pads had clusters; (maybe) skipping tracking attempt";
464 ldmx_log(debug) <<
"Done with tracking step. ";
467 event.add(output_collection_, cleanedTracks);
470 event.add(output_collection_ +
"Y", cleanedTracksY);
471 event.add(output_collection_ +
"X", cleanedTracksX);
479 std::vector<ldmx::TrigScintCluster> clusters) {
490 for (uint i = 0; i < clusters.size(); i++) {
491 centroid += (clusters.at(i)).getCentroid();
492 centroidX += (clusters.at(i)).getCentroidX();
493 centroidY += (clusters.at(i)).getCentroidY();
495 beamEfrac += (clusters.at(i)).getBeamEfrac();
496 pe += (clusters.at(i)).getPE();
498 centroid /= clusters.size();
499 centroidX /= clusters.size();
500 if (centroid >= vertBarStartIdx_) {
503 <<
" -- In makeTrack made vertical bar track with centroid "
504 << centroid <<
" and y flag sum " << centroidY;
516 centroidY = (centroidY + 1) * 2 * nBarsY_ / 8.;
520 if (verbose_) ldmx_log(debug) <<
" -- new centroidY = " << centroidY;
522 centroidY /= clusters.size();
524 beamEfrac /= clusters.size();
525 pe /= clusters.size();
528 for (uint i = 0; i < clusters.size(); i++)
529 residual += ((clusters.at(i)).getCentroid() - centroid) *
530 ((clusters.at(i)).getCentroid() - centroid);
531 residual = sqrt(residual / clusters.size());
541 ldmx_log(debug) <<
" -- In makeTrack made track with centroid "
542 << centroid <<
" and residual " << residual <<
" and pe "
543 << pe <<
" from clusters with centroids";
544 for (uint i = 0; i < clusters.size(); i++)
545 ldmx_log(debug) <<
"\tpad " << i <<
": centroid "
546 << (clusters.at(i)).getCentroid();
553void TrigScintTrackProducer::matchXYTracks(
554 std::vector<ldmx::TrigScintTrack> &tracks) {
556 std::multimap<int, int>
558 std::multimap<int, int> xIdxQuadMap;
560 std::multimap<int, ldmx::TrigScintTrack> yQuadMap;
561 std::multimap<int, ldmx::TrigScintTrack> xQuadMap;
564 std::map<ldmx::TrigScintTrack, int> yTrackMap;
565 std::map<ldmx::TrigScintTrack, int> xTrackMap;
568 for (
auto trk : tracks) {
571 if (trk.getCentroidX() == -1) {
573 ldmx_log(debug) <<
" -- In matchXYTracks found y track at "
574 << trk.getCentroidY() <<
"; mapping to quad "
575 << (int)trk.getCentroidY() / 8 <<
" with trk index "
579 yQuadMap.insert(std::make_pair((
int)(trk.getCentroidY() / 8), trk));
580 yTrackMap[trk] = trkIdx;
581 yIdxQuadMap.insert(std::make_pair((
int)(trk.getCentroidY() / 8), trkIdx));
585 xQuadMap.insert(std::make_pair((
int)(trk.getCentroidY() / 8), trk));
586 xTrackMap[trk] = trkIdx;
587 xIdxQuadMap.insert(std::make_pair((
int)(trk.getCentroidY() / 8), trkIdx));
589 ldmx_log(debug) <<
" -- In matchXYTracks found x track at (x,y) = ("
590 << trk.getCentroidX() <<
", " << trk.getCentroidY()
591 <<
"); mapping to quad " << (int)trk.getCentroidY() / 8
592 <<
" with trk index " << trkIdx;
605 float sx0 = fabs(xStart_);
607 float sy0 = fabs(yStart_) /
612 for (
auto yitr = yQuadMap.begin(); yitr != yQuadMap.end(); ++yitr) {
613 int nYinQuad = yQuadMap.count((*yitr).first);
614 int nXinQuad = xQuadMap.count((*yitr).first);
615 float y{-9999.}, sy{-9999.}, x{-9999.}, x1{-9999.}, x2{-9999.}, sx1{-9999.},
616 sx2{-9999.}, y1{-9999.}, y2{-9999.}, sy1{-9999.}, sy2{-9999.};
618 float y0 = (*yitr).first * 8 + sy0;
620 1. / 2 * xConvFactor_;
630 ldmx_log(debug) <<
"\t\t\t no x info in quad " << (*yitr).first
631 <<
"; will set x to middle of pad, pad half-width as "
632 "precision: set (x, sx)=("
633 << x <<
", " << sx <<
")";
640 auto xitr = xQuadMap.find((*yitr).first);
641 x = ((*xitr).second).getCentroidX() * xConvFactor_ + xStart_;
644 ldmx_log(debug) <<
"\t\t\t 1 x in quad " << (*yitr).first
645 <<
", getting (x, sx)=(" << x <<
", " << sx <<
")";
647 else if (nXinQuad == 2) {
652 auto xitr1 = xQuadMap.lower_bound((*yitr).first);
653 auto xitr2 = xQuadMap.upper_bound((*yitr).first);
656 if (xitr1 != xitr2) {
657 x1 = ((*xitr1).second).getCentroidX() * xConvFactor_ + xStart_;
658 x2 = ((*xitr2).second).getCentroidX() * xConvFactor_ + xStart_;
659 sx1 = xConvFactor_ / 2.;
662 sx = fabs(x1 - x2) / 2 *
665 ldmx_log(debug) <<
"\t\t -- 2 x in quad: setting y track x "
666 "coordinate to midpoint";
674 y = ((*yitr).second).getCentroidY() * yConvFactor_ + yStart_;
675 sy = ((*yitr).second).getResidual() * yConvFactor_;
677 sy = 1. / 2 * yConvFactor_;
684 auto xidx = xIdxQuadMap.find((*yitr).first);
685 auto yidx = yIdxQuadMap.find((*yitr).first);
686 tracks.at((*xidx).second).setPosition(x, y);
687 tracks.at((*xidx).second).setSigmaXY(sx, sy);
688 tracks.at((*yidx).second).setPosition(x, y);
689 tracks.at((*yidx).second).setSigmaXY(sx, sy);
691 ldmx_log(debug) <<
"\t\t\t in quad " << (*yitr).first
692 <<
", set (x, y) = (" << x <<
", " << y
693 <<
") and (sx, sy) = " << sx <<
", " << sy <<
")";
699 ldmx_log(debug) <<
"\t\t in quad " << (*yitr).first
700 <<
", not single x,y tracks: " << nXinQuad <<
" of x and "
701 << nYinQuad <<
" of y";
706 auto yitr1 = yQuadMap.lower_bound((*yitr).first);
707 auto yitr2 = yQuadMap.upper_bound((*yitr).first);
709 y1 = ((*yitr1).second).getCentroidY() * yConvFactor_ + yStart_;
710 y2 = ((*yitr2).second).getCentroidY() * yConvFactor_ + yStart_;
711 sy1 = ((*yitr1).second).getResidual() * yConvFactor_;
712 sy2 = ((*yitr2).second).getResidual() * yConvFactor_;
714 sy = fabs(y1 - y2) / 2 * yConvFactor_;
717 <<
"\t\t -- 2 y in quad: setting x track y coordinate to midpoint";
726 auto yidx = yIdxQuadMap.find((*yitr).first);
727 tracks.at((*yidx).second).setPosition(x, y);
728 tracks.at((*yidx).second).setSigmaXY(sx, sy);
730 int minOverlapPE_ = 250;
731 if (((*yitr).second).getPE() < minOverlapPE_) {
738 ldmx_log(debug) <<
"\t\t -- Can't tell which x track should be "
739 "matched to single y track. Setting both x track "
740 "coordinates to y quadrant value:";
743 ldmx_log(debug) <<
"\t\t -- Found large PE count ("
744 << ((*yitr).second).getPE() <<
" > " << minOverlapPE_
745 <<
"), suggesting overlap! Setting both x track "
746 "coordinates to y track value:";
753 ldmx_log(debug) <<
"\t\t -- (x1, x2, y) = (" << x1 <<
", " << x2
754 <<
", " << y <<
") and (sx1, sx2, sy) = " << sx1 <<
", "
755 << sx2 <<
", " << sy <<
")";
758 auto xidx1 = xIdxQuadMap.lower_bound((*yitr).first);
759 auto xidx2 = xIdxQuadMap.upper_bound((*yitr).first);
761 tracks.at((*xidx1).second).setPosition(x1, y);
762 tracks.at((*xidx1).second).setSigmaXY(sx1, sy);
763 tracks.at((*xidx2).second).setPosition(x2, y);
764 tracks.at((*xidx2).second).setSigmaXY(sx2, sy);
767 else if (nYinQuad == 2 && nXinQuad == 1) {
772 auto xidx = xIdxQuadMap.find((*yitr).first);
773 tracks.at((*xidx).second).setPosition(x, y);
774 tracks.at((*xidx).second).setSigmaXY(sx, sy);
776 auto xitr = xQuadMap.lower_bound((*yitr).first);
777 int minOverlapPE_ = 300;
778 if (((*xitr).second).getPE() < minOverlapPE_) {
781 <<
"\t\t just 1 x track with not-unusual PE in the quad -- can't "
782 "match; setting mid-point values for x ";
792 ldmx_log(debug) <<
"\t\t -- Found large PE count ("
793 << ((*xitr).second).getPE() <<
" > " << minOverlapPE_
794 <<
") in x track, suggesting overlap! Setting both y "
795 "track coordinates to x track value:";
798 ldmx_log(debug) <<
"\t\t -- (x, y1, y2) = (" << x <<
", " << y1 <<
", "
799 << y2 <<
") and (sx, sy1, sy2) = " << sx <<
", " << sy1
800 <<
", " << sy2 <<
")";
802 auto yidx1 = yIdxQuadMap.lower_bound((*yitr).first);
803 auto yidx2 = yIdxQuadMap.upper_bound((*yitr).first);
805 tracks.at((*yidx1).second).setPosition(x, y1);
806 tracks.at((*yidx1).second).setSigmaXY(sx, sy1);
807 tracks.at((*yidx2).second).setPosition(x, y2);
808 tracks.at((*yidx2).second).setSigmaXY(sx, sy2);
811 else if (nYinQuad == 2 && nXinQuad == 2) {
813 auto xidx1 = xIdxQuadMap.lower_bound((*yitr).first);
814 auto xidx2 = xIdxQuadMap.upper_bound((*yitr).first);
816 auto yidx1 = yIdxQuadMap.lower_bound((*yitr).first);
817 auto yidx2 = yIdxQuadMap.upper_bound((*yitr).first);
820 if (yIdxQuadMap.find((*yitr).first) == yIdxQuadMap.end())
821 ldmx_log(error) <<
"The two y tracks in the same quadrant at "
823 <<
" appear to not be found in the y track map! "
824 "investigate. Note that yidx1.first = "
826 <<
" and yidx2.first = " << (*yidx2).first;
828 tracks.at((*xidx1).second).setPosition(x1, y);
829 tracks.at((*xidx1).second).setSigmaXY(sx1, sy);
830 tracks.at((*xidx2).second).setPosition(x2, y);
831 tracks.at((*xidx2).second).setSigmaXY(sx2, sy);
833 tracks.at((*yidx1).second).setPosition(x, y1);
834 tracks.at((*yidx1).second).setSigmaXY(sx, sy1);
835 tracks.at((*yidx2).second).setPosition(x, y2);
836 tracks.at((*yidx2).second).setSigmaXY(sx, sy2);
839 ldmx_log(debug) <<
"\t\t -- in a 2 x 2 situaiton; midpoint y: " << y
840 <<
" for both x tracks, midpoint x: " << x
841 <<
" for both y tracks";
847 ldmx_log(debug) <<
"\t\t -*-*-*- more than 2 x tracks in the same quad "
848 "-- nothing done about the x,y coordinates in this "
849 "situation -- implement if needed!!";
853 ldmx_log(debug) <<
"\t\t -*-*-*- more than 2 y tracks in the same quad "
854 "-- nothing done about the x,y coordinates in this "
855 "situation -- implement if needed!!";
867 ldmx_log(debug) <<
"Process starts!";
873 ldmx_log(debug) <<
"Process ends!";
#define DECLARE_PRODUCER_NS(NS, CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
Implements an event buffer system for storing event data.
bool exists(const std::string &name, const std::string &passName="", bool unique=true) const
Check for the existence of an object or collection with the given name and pass name in the event.
Class encapsulating parameters for configuring a processor.
T getParameter(const std::string &name) const
Retrieve the parameter of the given name.
Stores cluster information from the trigger scintillator pads.
Represents a track of trigger scintillator clusters.
void setCentroidX(float centroid)
Set the x centroid of the track.
void setResidual(float resid)
Set the detector ID residual of the track.
void setCentroidY(float centroid)
Set the y centroid of the track.
void setPE(float pe)
Set the average cluster pe of the track.
float getCentroid() const
Get the detector ID centroid of the track.
void addConstituent(TrigScintCluster cl)
Add a cluster to the list of track constituents.
void setCentroid(float centroid)
Set the detector ID centroid of the track.
void setBeamEfrac(float e)
Set beam energy fraction of hit.
std::vector< ldmx::TrigScintCluster > getConstituents() const
Get the cluster constituents of the track.
void configure(framework::config::Parameters &ps) override
Callback for the EventProcessor to configure itself from the given set of parameters.
void onProcessEnd() override
Callback for the EventProcessor to take any necessary action when the processing of events finishes,...
void produce(framework::Event &event) override
Process the event and put new data products into it.
void onProcessStart() override
Callback for the EventProcessor to take any necessary action when the processing of events starts,...