LDMX Software
TrigScintFirmwareTracker.cxx
1
3
4#include <iterator>
5#include <map>
6
7#include "TrigScint/Firmware/clusterproducer.h"
8#include "TrigScint/Firmware/objdef.h"
9#include "TrigScint/Firmware/trackproducer.h"
10
11namespace trigscint {
12
14 minThr_ = ps.getParameter<double>("clustering_threshold");
15 digis1_collection_ = ps.getParameter<std::string>("digis1_collection");
16 digis2_collection_ = ps.getParameter<std::string>("digis2_collection");
17 digis3_collection_ = ps.getParameter<std::string>("digis3_collection");
18 passName_ = ps.getParameter<std::string>("input_pass_name");
19 output_collection_ = ps.getParameter<std::string>("output_collection");
20 verbose_ = ps.getParameter<int>("verbosity");
21 timeTolerance_ = ps.getParameter<double>("time_tolerance");
22 padTime_ = ps.getParameter<double>("pad_time");
23 if (verbose_) {
24 ldmx_log(info) << "In TrigScintFirmwareTracker: configure done!";
25 ldmx_log(info) << "\nClustering threshold: " << minThr_
26 << "\nExpected pad hit time: " << padTime_
27 << "\nMax hit time delay: " << timeTolerance_
28 << "\ndigis1 collection: " << digis1_collection_
29 << "\ndigis2 collection: " << digis2_collection_
30 << "\ndigis3 collection: " << digis3_collection_
31 << "\nInput pass name: " << passName_
32 << "\nOutput collection: " << output_collection_
33 << "\nVerbosity: " << verbose_;
34 }
35
36 return;
37}
38
40 // This processor takes in TS digis and outputs a track collection. It does so
41 // using clusterproducer_sw and trackproducer_hw, which are validated pieces
42 // of HLS code (though clusterproducer_sw has had its instances of pragmas
43 // excluded. I will comment on how clusterproducer and trackproducer work more
44 // thouroughly in them respectively, but generally the clusterproducer makes
45 // only two hit clusters (as ready that was all that was made from the
46 // original sw) and does so by making a digi map and running along channels
47 // numerically and pairing if possible. The trackproducer takes a LOOKUP array
48 // as a LUT and does track pattern mathcing. This depends on alignment through
49 // the A vector below.
50
51 if (verbose_) {
52 ldmx_log(debug)
53 << "TrigScintFirmwareTracker: produce() starts! Event number: "
54 << event.getEventHeader().getEventNumber();
55 }
56
57 // A is the mis-alignment vector
58 ap_int<12> A[3] = {0, 0, 0};
59 ap_int<12> LOOKUP[NCENT][COMBO][2];
60
61 // Initialize the LOOKUP table to zero
62 for (int i = 0; i < NCENT; ++i) {
63 for (int j = 0; j < COMBO; ++j) {
64 for (int k = 0; k < 2; ++k) {
65 LOOKUP[i][j][k] = ap_int<12>(-1);
66 }
67 }
68 }
69
70 // This line fills in the LOOKUP table used for patter matching latter. The
71 // array takes in as its first argument the centroid of a first pad cluster,
72 // then the next two take on which track pattern (of ~9) we are matching to
73 // and the last if we are matching to a cluster with two hits
74 for (int i = 0; i < NCENT; i++) {
75 for (int j = 0; j < COMBO; j++) {
76 LOOKUP[i][j][0] = (i - A[1] + A[0]);
77 LOOKUP[i][j][1] = (i - A[2] + A[0]);
78 if (j / 3 == 0) {
79 LOOKUP[i][j][0] -= 1;
80 } else if (j / 3 == 2) {
81 LOOKUP[i][j][0] += 1;
82 }
83 if (j % 3 == 0) {
84 LOOKUP[i][j][1] -= 1;
85 } else if (j % 3 == 2) {
86 LOOKUP[i][j][1] += 1;
87 }
88 if (not((LOOKUP[i][j][0] >= 0) and (LOOKUP[i][j][1] >= 0) and
89 (LOOKUP[i][j][0] < NCENT) and (LOOKUP[i][j][1] < NCENT))) {
90 LOOKUP[i][j][0] = -1;
91 LOOKUP[i][j][1] = -1;
92 }
93 }
94 }
95 // Here we instantiate arrays necessary to do the rest of it.
96 Hit HPad1[NHITS];
97 Hit HPad2[NHITS];
98 Hit HPad3[NHITS];
99
100 // Pad1 goes with NTRK bc of firmware bandwidth constraints
101 // It is also expected on Pad1 to have 1 cluster per track
102 Cluster Pad1[NTRK];
103 Cluster Pad2[NCLUS];
104 Cluster Pad3[NCLUS];
105 Track outTrk[NTRK];
106
107 for (int j = 0; j < NHITS; j++) {
108 clearHit(HPad1[j]);
109 clearHit(HPad2[j]);
110 clearHit(HPad3[j]);
111 }
112 for (int j = 0; j < NCLUS; j++) {
113 if (j < NTRK) {
114 clearClus(Pad1[j]);
115 }
116 clearClus(Pad2[j]);
117 clearClus(Pad3[j]);
118 }
119 for (int j = 0; j < NTRK; j++) {
120 clearTrack(outTrk[j]);
121 }
122 // I am reading in the three digi collections
123 const auto &digis1{
124 event.getCollection<ldmx::TrigScintHit>(digis1_collection_, passName_)};
125 const auto &digis2{
126 event.getCollection<ldmx::TrigScintHit>(digis2_collection_, passName_)};
127 const auto &digis3{
128 event.getCollection<ldmx::TrigScintHit>(digis3_collection_, passName_)};
129
130 if (verbose_) {
131 ldmx_log(debug) << "Got digi collection " << digis1_collection_ << "_"
132 << passName_ << " with " << digis1.size() << " entries ";
133 }
134
135 // The next collection of things fill in the firmware hit objects from reading
136 // in the digi collections the necessary information. The firmware hit objects
137 // only keep bID,mID,Time, and PE count.
138 int occupied[NCHAN];
139 for (int i = 0; i < NCHAN; i++) {
140 occupied[i] = -1;
141 }
142 int count = 0;
143 for (const auto &digi : digis1) {
144 if ((digi.getPE() > minThr_) and (digi.getBarID() <= NCHAN) and
145 (digi.getBarID() >= 0)) {
146 ap_int<12> bID = (ap_int<12>)(digi.getBarID());
147 ap_int<12> Amp = (ap_int<12>)(digi.getPE());
148 if (occupied[digi.getBarID()] >= 0) {
149 if (HPad1[occupied[digi.getBarID()]].Amp < digi.getPE()) {
150 HPad1[occupied[digi.getBarID()]].bID = (ap_int<12>)(digi.getBarID());
151 HPad1[occupied[digi.getBarID()]].mID =
152 (ap_int<12>)(digi.getModuleID());
153 HPad1[occupied[digi.getBarID()]].Amp = (ap_int<12>)(digi.getPE());
154 HPad1[occupied[digi.getBarID()]].Time = (ap_int<12>)(digi.getTime());
155 }
156 } else {
157 HPad1[count].bID = (ap_int<12>)(digi.getBarID());
158 HPad1[count].mID = (ap_int<12>)(digi.getModuleID());
159 HPad1[count].Amp = (ap_int<12>)(digi.getPE());
160 HPad1[count].Time = (ap_int<12>)(digi.getTime());
161 occupied[digi.getBarID()] = count;
162 count++;
163 }
164 }
165 }
166
167 for (int i = 0; i < NCHAN; i++) {
168 occupied[i] = -1;
169 }
170 count = 0;
171 for (const auto &digi : digis2) {
172 if ((digi.getPE() > minThr_) and (digi.getBarID() <= NCHAN) and
173 (digi.getBarID() >= 0)) {
174 ap_int<12> bID = (ap_int<12>)(digi.getBarID());
175 ap_int<12> Amp = (ap_int<12>)(digi.getPE());
176 if (occupied[digi.getBarID()] >= 0) {
177 if (HPad2[occupied[digi.getBarID()]].Amp < digi.getPE()) {
178 HPad2[occupied[digi.getBarID()]].bID = (ap_int<12>)(digi.getBarID());
179 HPad2[occupied[digi.getBarID()]].mID =
180 (ap_int<12>)(digi.getModuleID());
181 HPad2[occupied[digi.getBarID()]].Amp = (ap_int<12>)(digi.getPE());
182 HPad2[occupied[digi.getBarID()]].Time = (ap_int<12>)(digi.getTime());
183 }
184 } else {
185 HPad2[count].bID = (ap_int<12>)(digi.getBarID());
186 HPad2[count].mID = (ap_int<12>)(digi.getModuleID());
187 HPad2[count].Amp = (ap_int<12>)(digi.getPE());
188 HPad2[count].Time = (ap_int<12>)(digi.getTime());
189 occupied[digi.getBarID()] = count;
190 count++;
191 }
192 }
193 }
194 for (int i = 0; i < NCHAN; i++) {
195 occupied[i] = -1;
196 }
197 count = 0;
198 for (const auto &digi : digis3) {
199 if ((digi.getPE() > minThr_) and (digi.getBarID() <= NCHAN) and
200 (digi.getBarID() >= 0)) {
201 ap_int<12> bID = (ap_int<12>)(digi.getBarID());
202 ap_int<12> Amp = (ap_int<12>)(digi.getPE());
203 if (occupied[digi.getBarID()] >= 0) {
204 if (HPad3[occupied[digi.getBarID()]].Amp < digi.getPE()) {
205 HPad3[occupied[digi.getBarID()]].bID = (ap_int<12>)(digi.getBarID());
206 HPad3[occupied[digi.getBarID()]].mID =
207 (ap_int<12>)(digi.getModuleID());
208 HPad3[occupied[digi.getBarID()]].Amp = (ap_int<12>)(digi.getPE());
209 HPad3[occupied[digi.getBarID()]].Time = (ap_int<12>)(digi.getTime());
210 }
211 } else {
212 HPad3[count].bID = (ap_int<12>)(digi.getBarID());
213 HPad3[count].mID = (ap_int<12>)(digi.getModuleID());
214 HPad3[count].Amp = (ap_int<12>)(digi.getPE());
215 HPad3[count].Time = (ap_int<12>)(digi.getTime());
216 occupied[digi.getBarID()] = count;
217 count++;
218 }
219 }
220 }
221 // These next lines here calls clusterproducer_sw(HPad1), which is just the
222 // validated firmware module. Since ap_* class is messy, I had to do some
223 // post-call cleanup before looping over the clusters and putting them into
224 // Point i which is feed into track producer
225 int counterN = 0;
226 std::array<Cluster, NCLUS> Point1 = clusterproducer_sw(HPad1);
227 int topSeed = 0;
228 for (int i = 0; i < NCLUS; i++) {
229 if ((Point1[i].Seed.Amp < 450) and (Point1[i].Seed.Amp > 30) and
230 (Point1[i].Seed.bID < (NCHAN + 1)) and (Point1[i].Seed.bID >= 0) and
231 (Point1[i].Sec.Amp < 450) and (counterN < NTRK)) {
232 if (Point1[i].Seed.bID >= topSeed) {
233 cpyHit(Pad1[counterN].Seed, Point1[i].Seed);
234 cpyHit(Pad1[counterN].Sec, Point1[i].Sec);
235 calcCent(Pad1[counterN]);
236 counterN++;
237 topSeed = Point1[i].Seed.bID;
238 }
239 }
240 }
241 std::array<Cluster, NCLUS> Point2 = clusterproducer_sw(HPad2);
242 topSeed = 0;
243 for (int i = 0; i < NCLUS; i++) {
244 if ((Point2[i].Seed.Amp < 450) and (Point2[i].Seed.Amp > 30) and
245 (Point2[i].Seed.bID < (NCHAN + 1)) and (Point2[i].Seed.bID >= 0) and
246 (Point2[i].Sec.Amp < 450)) {
247 if (Point2[i].Seed.bID >= topSeed) {
248 cpyHit(Pad2[i].Seed, Point2[i].Seed);
249 cpyHit(Pad2[i].Sec, Point2[i].Sec);
250 calcCent(Pad2[i]);
251 topSeed = Point2[i].Seed.bID;
252 }
253 }
254 }
255 std::array<Cluster, NCLUS> Point3 = clusterproducer_sw(HPad3);
256 topSeed = 0;
257 for (int i = 0; i < NCLUS; i++) {
258 if ((Point3[i].Seed.Amp < 450) and (Point3[i].Seed.Amp > 30) and
259 (Point3[i].Seed.bID < (NCHAN + 1)) and (Point3[i].Seed.bID >= 0) and
260 (Point3[i].Sec.Amp < 450)) {
261 if (Point3[i].Seed.bID >= topSeed) {
262 cpyHit(Pad3[i].Seed, Point3[i].Seed);
263 cpyHit(Pad3[i].Sec, Point3[i].Sec);
264 calcCent(Pad3[i]);
265 topSeed = Point3[i].Seed.bID;
266 }
267 }
268 }
269 // I have stagged the digis into firmware digi objects and paired them into
270 // firmware cluster objects, so at this point I can insert them and the LUT
271 // into the trackproducer_hw to create the track collection I use makeTrack to
272 // revert the firmware track object back into a regular track object for
273 // analysis purposes
274 //
275 // NOTE: Pad1 has NTRK instead of NCLUS clusters for a reason: the firmware
276 // cannot facilitate NCLUS many tracks within its alloted bandwidth , we have
277 // to put a cut on them which is facilitated by a cut on the number of
278 // clusters in Pad1. Do not change this.
279 trackproducer_hw(Pad1, Pad2, Pad3, outTrk, LOOKUP);
280 for (int I = 0; I < NTRK; I++) {
281 if (outTrk[I].Pad1.Seed.Amp > 0. && outTrk[I].Pad1.Sec.Amp >= 0. &&
282 outTrk[I].Pad2.Seed.Amp > 0. && outTrk[I].Pad2.Sec.Amp >= 0. &&
283 outTrk[I].Pad3.Seed.Amp > 0. && outTrk[I].Pad3.Sec.Amp >= 0.) {
284 ldmx::TrigScintTrack trk = makeTrack(outTrk[I]);
285 tracks_.push_back(trk);
286 }
287 }
288 event.add(output_collection_, tracks_);
289 tracks_.resize(0);
290
291 return;
292}
293
294ldmx::TrigScintTrack TrigScintFirmwareTracker::makeTrack(Track outTrk) {
295 // This takes a firmware track object and reverts it into an ldmx track
296 // object, unfortunately only retaining that information of the track that is
297 // retained in the firmware track.
299 float pe{0.};
300 pe += static_cast<float>(outTrk.Pad1.Seed.Amp) +
301 static_cast<float>(outTrk.Pad1.Sec.Amp);
302 pe += static_cast<float>(outTrk.Pad2.Seed.Amp) +
303 static_cast<float>(outTrk.Pad2.Sec.Amp);
304 pe += static_cast<float>(outTrk.Pad3.Seed.Amp) +
305 static_cast<float>(outTrk.Pad3.Sec.Amp);
306 tr.setCentroid(calcTCent(outTrk));
307 calcResid(outTrk);
308 tr.setPE(pe);
309 return tr;
310}
311
312} // namespace trigscint
313
314DECLARE_PRODUCER_NS(trigscint, TrigScintFirmwareTracker);
#define DECLARE_PRODUCER_NS(NS, CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
Tracker made to emulate and stage real firmware, emulates existing ldmx software but has LUT structur...
Implements an event buffer system for storing event data.
Definition Event.h:41
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:27
T getParameter(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:89
Represents a track of trigger scintillator clusters.
void setPE(float pe)
Set the average cluster pe of the track.
void setCentroid(float centroid)
Set the detector ID centroid of the track.
void produce(framework::Event &event) override
Process the event and put new data products into it.
double minThr_
add a hit at index idx to a cluster
void configure(framework::config::Parameters &ps) override
Callback for the EventProcessor to configure itself from the given set of parameters.
Definition objdef.h:49
Sign Arbitrary Precision Type.
Definition ap_int.h:28