Belle II Software  release-06-02-00
NeuroTrigger.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 #include <framework/logging/Logger.h>
9 #include <trg/cdc/NeuroTrigger.h>
10 
11 #include <cdc/geometry/CDCGeometryPar.h>
12 #include <framework/gearbox/Const.h>
13 #include <framework/gearbox/Unit.h>
14 #include <framework/datastore/StoreObjPtr.h>
15 #include <framework/datastore/StoreArray.h>
16 #include <trg/cdc/dbobjects/CDCTriggerNeuroConfig.h>
17 #include <trg/cdc/dataobjects/CDCTriggerTrack.h>
18 #include <string>
19 #include <cmath>
20 #include <TFile.h>
21 
22 
23 using namespace Belle2;
24 using namespace CDC;
25 using namespace std;
26 
27 void
29 {
30  // check parameters
31  bool okay = true;
32  // ensure that length of lists matches number of sectors
33  if (p.nHidden.size() != 1 && p.nHidden.size() != p.nMLP) {
34  B2ERROR("Number of nHidden lists should be 1 or " << p.nMLP);
35  okay = false;
36  }
37  if (p.outputScale.size() != 1 && p.outputScale.size() != p.nMLP) {
38  B2ERROR("Number of outputScale lists should be 1 or " << p.nMLP);
39  okay = false;
40  }
41  bool rangeProduct = (p.phiRange.size() * p.invptRange.size() * p.thetaRange.size() * p.SLpattern.size() == p.nMLP);
42  if (!rangeProduct) {
43  if (p.phiRange.size() != 1 && p.phiRange.size() != p.nMLP) {
44  B2ERROR("Number of phiRange lists should be 1 or " << p.nMLP);
45  okay = false;
46  }
47  if (p.invptRange.size() != 1 && p.invptRange.size() != p.nMLP) {
48  B2ERROR("Number of invptRange lists should be 1 or " << p.nMLP);
49  okay = false;
50  }
51  if (p.thetaRange.size() != 1 && p.thetaRange.size() != p.nMLP) {
52  B2ERROR("Number of thetaRange lists should be 1 or " << p.nMLP);
53  okay = false;
54  }
55  if (p.SLpattern.size() != 1 && p.SLpattern.size() != p.nMLP) {
56  B2ERROR("Number of SLpattern lists should be 1 or " << p.nMLP);
57  okay = false;
58  }
59  }
60  // ensure that length of maxHitsPerSL and SLpatternMask lists matches SLpattern
61  if (p.maxHitsPerSL.size() != 1 && p.maxHitsPerSL.size() != p.SLpattern.size()) {
62  B2ERROR("Number of maxHitsPerSL lists should be 1 or " << p.SLpattern.size());
63  okay = false;
64  }
65  if (p.SLpatternMask.size() != 1 && p.SLpatternMask.size() != p.SLpattern.size()) {
66  B2ERROR("Number of SLpatternMask lists should be 1 or " << p.SLpattern.size());
67  okay = false;
68  }
69  // ensure that number of target nodes is valid
70  unsigned short nTarget = int(p.targetZ) + int(p.targetTheta);
71  if (nTarget < 1) {
72  B2ERROR("No outputs! Turn on either targetZ or targetTheta.");
73  okay = false;
74  }
75  // ensure that sector ranges are valid
76  for (unsigned iPhi = 0; iPhi < p.phiRange.size(); ++iPhi) {
77  if (p.phiRange[iPhi].size() != 2) {
78  B2ERROR("phiRange should be exactly 2 values");
79  okay = false;
80  continue;
81  }
82  if (p.phiRange[iPhi][0] >= p.phiRange[iPhi][1]) {
83  B2ERROR("phiRange[0] should be smaller than phiRange[1]");
84  okay = false;
85  }
86  if (p.phiRange[iPhi][0] < -360. || p.phiRange[iPhi][1] > 360. ||
87  (p.phiRange[iPhi][1] - p.phiRange[iPhi][0]) > 360.) {
88  B2ERROR("phiRange should be in [-360, 360], with maximal width of 360");
89  okay = false;
90  }
91  }
92  for (unsigned iPt = 0; iPt < p.invptRange.size(); ++iPt) {
93  if (p.invptRange[iPt].size() != 2) {
94  B2ERROR("invptRange should be exactly 2 values");
95  okay = false;
96  }
97  if (p.invptRange[iPt][0] >= p.invptRange[iPt][1]) {
98  B2ERROR("invptRange[0] should be smaller than invptRange[1]");
99  okay = false;
100  }
101  }
102  for (unsigned iTheta = 0; iTheta < p.thetaRange.size(); ++iTheta) {
103  if (p.thetaRange[iTheta].size() != 2) {
104  B2ERROR("thetaRange should be exactly 2 values");
105  okay = false;
106  continue;
107  }
108  if (p.thetaRange[iTheta][0] >= p.thetaRange[iTheta][1]) {
109  B2ERROR("thetaRange[0] should be smaller than thetaRange[1]");
110  okay = false;
111  }
112  if (p.thetaRange[iTheta][0] < 0. || p.thetaRange[iTheta][1] > 180.) {
113  B2ERROR("thetaRange should be in [0, 180]");
114  okay = false;
115  }
116  }
117  for (unsigned iScale = 0; iScale < p.outputScale.size(); ++iScale) {
118  if (p.outputScale[iScale].size() != 2 * nTarget) {
119  B2ERROR("outputScale should be exactly " << 2 * nTarget << " values");
120  okay = false;
121  }
122  }
123  // ensure that train sectors are valid
124  if (p.phiRange.size() != p.phiRangeTrain.size()) {
125  B2ERROR("Number of phiRange lists and phiRangeTrain lists should be equal.");
126  okay = false;
127  } else {
128  for (unsigned iPhi = 0; iPhi < p.phiRange.size(); ++iPhi) {
129  if (p.phiRangeTrain[iPhi].size() != 2) {
130  B2ERROR("phiRangeTrain should be exactly 2 values.");
131  okay = false;
132  } else if (p.phiRangeTrain[iPhi][0] > p.phiRange[iPhi][0] ||
133  p.phiRangeTrain[iPhi][1] < p.phiRange[iPhi][1]) {
134  B2ERROR("phiRangeTrain should be wider than phiRange or equal.");
135  okay = false;
136  }
137  }
138  }
139  if (p.invptRange.size() != p.invptRangeTrain.size()) {
140  B2ERROR("Number of invptRange lists and invptRangeTrain lists should be equal.");
141  okay = false;
142  } else {
143  for (unsigned iPt = 0; iPt < p.invptRange.size(); ++iPt) {
144  if (p.invptRangeTrain[iPt].size() != 2) {
145  B2ERROR("invptRangeTrain should be exactly 2 values.");
146  okay = false;
147  } else if (p.invptRangeTrain[iPt][0] > p.invptRange[iPt][0] ||
148  p.invptRangeTrain[iPt][1] < p.invptRange[iPt][1]) {
149  B2ERROR("invptRangeTrain should be wider than invptRange or equal.");
150  okay = false;
151  }
152  }
153  }
154  if (p.thetaRange.size() != p.thetaRangeTrain.size()) {
155  B2ERROR("Number of thetaRange lists and thetaRangeTrain lists should be equal.");
156  okay = false;
157  } else {
158  for (unsigned iTheta = 0; iTheta < p.thetaRange.size(); ++iTheta) {
159  if (p.thetaRangeTrain[iTheta].size() != 2) {
160  B2ERROR("thetaRangeTrain should be exactly 2 values.");
161  okay = false;
162  } else if (p.thetaRangeTrain[iTheta][0] > p.thetaRange[iTheta][0] ||
163  p.thetaRangeTrain[iTheta][1] < p.thetaRange[iTheta][1]) {
164  B2ERROR("thetaRangeTrain should be wider than thetaRange or equal.");
165  okay = false;
166  }
167  }
168  }
169 
170  if (!okay) return;
171 
172  // initialize MLPs
173  m_MLPs.clear();
174  for (unsigned iMLP = 0; iMLP < p.nMLP; ++iMLP) {
175  //get indices for sector parameters
176  vector<unsigned> indices = getRangeIndices(p, iMLP);
177  //get number of nodes for each layer
178  unsigned short maxHits = (p.maxHitsPerSL.size() == 1) ? p.maxHitsPerSL[0] : p.maxHitsPerSL[indices[3]];
179  unsigned long SLpattern = p.SLpattern[indices[3]];
180  unsigned long SLpatternMask = (p.SLpatternMask.size() == 1) ? p.SLpatternMask[0] : p.SLpatternMask[indices[3]];
181  unsigned short nInput = 27 * maxHits;
182  vector<float> nHidden = (p.nHidden.size() == 1) ? p.nHidden[0] : p.nHidden[iMLP];
183  vector<unsigned short> nNodes = {nInput};
184  for (unsigned iHid = 0; iHid < nHidden.size(); ++iHid) {
185  if (p.multiplyHidden) {
186  nNodes.push_back(nHidden[iHid] * nNodes[0]);
187  } else {
188  nNodes.push_back(nHidden[iHid]);
189  }
190  }
191  nNodes.push_back(nTarget);
192  unsigned short targetVars = int(p.targetZ) + (int(p.targetTheta) << 1);
193  //get sector ranges (initially train ranges)
194  vector<float> phiRange = p.phiRangeTrain[indices[0]];
195  vector<float> invptRange = p.invptRangeTrain[indices[1]];
196  vector<float> thetaRange = p.thetaRangeTrain[indices[2]];
197  B2DEBUG(50, "Ranges for sector " << iMLP
198  << ": phiRange [" << phiRange[0] << ", " << phiRange[1]
199  << "], invptRange [" << invptRange[0] << ", " << invptRange[1]
200  << "], thetaRange [" << thetaRange[0] << ", " << thetaRange[1]
201  << "], SLpattern " << SLpattern);
202  //get scaling values
203  vector<float> outputScale = (p.outputScale.size() == 1) ? p.outputScale[0] : p.outputScale[iMLP];
204  //convert phi and theta from degree to radian
205  phiRange[0] *= Unit::deg;
206  phiRange[1] *= Unit::deg;
207  thetaRange[0] *= Unit::deg;
208  thetaRange[1] *= Unit::deg;
209  if (p.targetTheta) {
210  outputScale[2 * int(p.targetZ)] *= Unit::deg;
211  outputScale[2 * int(p.targetZ) + 1] *= Unit::deg;
212  }
213  //create new MLP
214  m_MLPs.push_back(CDCTriggerMLP(nNodes, targetVars, outputScale,
215  phiRange, invptRange, thetaRange,
216  maxHits, SLpattern, SLpatternMask, p.tMax, p.T0fromHits,
217  p.et_option));
218  }
219  // load some values from the geometry that will be needed for the input
220  setConstants();
221 }
222 
223 vector<unsigned>
224 NeuroTrigger::getRangeIndices(const Parameters& p, unsigned isector)
225 {
226  std::vector<unsigned> indices = {0, 0, 0, 0};
227  if (p.phiRange.size() * p.invptRange.size() * p.thetaRange.size() * p.SLpattern.size() == p.nMLP) {
228  indices[0] = isector % p.phiRange.size();
229  indices[1] = (isector / p.phiRange.size()) % p.invptRange.size();
230  indices[2] = (isector / (p.phiRange.size() * p.invptRange.size())) % p.thetaRange.size();
231  indices[3] = isector / (p.phiRange.size() * p.invptRange.size() * p.thetaRange.size());
232  } else {
233  indices[0] = (p.phiRange.size() == 1) ? 0 : isector;
234  indices[1] = (p.invptRange.size() == 1) ? 0 : isector;
235  indices[2] = (p.thetaRange.size() == 1) ? 0 : isector;
236  indices[3] = (p.SLpattern.size() == 1) ? 0 : isector;
237  }
238  return indices;
239 }
240 
241 void
243 {
245  int layerId = 3;
246  int nTS = 0;
247  for (int iSL = 0; iSL < 9; ++iSL) {
248  m_TSoffset[iSL] = nTS;
249  nTS += cdc.nWiresInLayer(layerId);
250  m_TSoffset[iSL + 1] = nTS;
251  for (int priority = 0; priority < 2; ++ priority) {
252  m_radius[iSL][priority] = cdc.senseWireR(layerId + priority);
253  }
254  layerId += (iSL > 0 ? 6 : 7);
255  }
256 }
257 
258 void
259 NeuroTrigger::initializeCollections(string hitCollectionName, string eventTimeName, const std::string& et_option)
260 {
261  m_segmentHits.isRequired(hitCollectionName);
262  if (!((et_option == "fastestpriority") || (et_option == "zero") || (et_option == "fastest2d"))) {
263  m_eventTime.isRequired(eventTimeName);
264  }
265  m_hitCollectionName = hitCollectionName;
266 }
267 
268 vector<int>
269 NeuroTrigger::selectMLPs(float phi0, float invpt, float theta)
270 {
271  vector<int> indices = {};
272 
273  if (m_MLPs.size() == 0) {
274  B2WARNING("Trying to select MLP before initializing MLPs.");
275  return indices;
276  }
277 
278  // find all matching sectors
279  for (unsigned isector = 0; isector < m_MLPs.size(); ++isector) {
280  if (m_MLPs[isector].inPhiRange(phi0) && m_MLPs[isector].inInvptRange(invpt)
281  && m_MLPs[isector].inThetaRange(theta)) {
282  indices.push_back(isector);
283  }
284  }
285 
286  if (indices.size() == 0) {
287  B2DEBUG(150, "Track does not match any sector.");
288  B2DEBUG(150, "invpt=" << invpt << ", phi=" << phi0 * 180. / M_PI << ", theta=" << theta * 180. / M_PI);
289  }
290 
291  return indices;
292 }
293 
294 
295 int
296 NeuroTrigger::selectMLPbyPattern(std::vector<int>& MLPs, unsigned long pattern, const bool neurotrackinputmode)
297 {
298  if (MLPs.size() == 0) {
299  return -1;
300  }
301 
302  int bestIndex = -1;
303  for (unsigned i = 0; i < MLPs.size(); ++i) {
304  int isector = MLPs[i];
305  unsigned long sectorPattern = m_MLPs[isector].getSLpattern();
306  B2DEBUG(250, "hitPattern " << pattern << " sectorPattern " << sectorPattern);
307  // no hit pattern restriction -> keep looking for exact match
308  if (sectorPattern == 0) {
309  B2DEBUG(250, "found match for general sector");
310  bestIndex = isector;
311  }
312  // exact match -> keep this sector and stop searching
313  if (pattern == sectorPattern) {
314  B2DEBUG(250, "found match for hit pattern " << pattern);
315  bestIndex = isector;
316  break;
317  }
318  }
319 
320  if (bestIndex < 0) {
321  if (neurotrackinputmode) {
322  B2DEBUG(150, "No sector found to match pattern, using sector 0" << pattern << ".");
323  bestIndex = 0;
324  } else {
325  B2DEBUG(150, "No sector found to match pattern " << pattern << ".");
326  }
327  }
328  return bestIndex;
329 }
330 
331 
332 void
334 {
335  double omega = track.getOmega(); // signed track curvature
336  for (int iSL = 0; iSL < 9; ++iSL) {
337  for (int priority = 0; priority < 2; ++priority) {
338  m_alpha[iSL][priority] = (m_radius[iSL][priority] * abs(omega) < 2.) ?
339  asin(m_radius[iSL][priority] * omega / 2.) :
340  M_PI_2;
341  m_idRef[iSL][priority] = remainder(((track.getPhi0() - m_alpha[iSL][priority]) *
342  (m_TSoffset[iSL + 1] - m_TSoffset[iSL]) / 2. / M_PI),
343  (m_TSoffset[iSL + 1] - m_TSoffset[iSL]));
344  }
345  }
346 }
347 
348 void
350 {
351  unsigned precisionPhi = m_precision[0];
352  unsigned precisionAlpha = m_precision[0];
353  unsigned precisionScale = m_precision[1];
354  unsigned precisionId = m_precision[2];
355 
356  double omega = track.getOmega();
357  long phi = round(track.getPhi0() * (1 << precisionPhi));
358 
359  for (int iSL = 0; iSL < 9; ++iSL) {
360  for (int priority = 0; priority < 2; ++priority) {
361  // LUT, calculated on the fly here
362  m_alpha[iSL][priority] =
363  (m_radius[iSL][priority] * abs(omega) < 2) ?
364  round(asin(m_radius[iSL][priority] * omega / 2) * (1 << precisionAlpha)) :
365  round(M_PI_2 * (1 << precisionAlpha));
366  long dphi = (precisionAlpha >= precisionPhi) ?
367  phi - (long(m_alpha[iSL][priority]) >> (precisionAlpha - precisionPhi)) :
368  phi - (long(m_alpha[iSL][priority]) << (precisionPhi - precisionAlpha));
369  m_idRef[iSL][priority] =
370  long(dphi * round((m_TSoffset[iSL + 1] - m_TSoffset[iSL]) / 2. / M_PI * (1 << precisionScale)) /
371  (long(1) << (precisionPhi + precisionScale - precisionId)));
372  // unscale after rounding
373  m_alpha[iSL][priority] /= (1 << precisionAlpha);
374  m_idRef[iSL][priority] /= (1 << precisionId);
375  }
376  }
377 }
378 
379 double
381 {
382  int iSL = hit.getISuperLayer();
383  int priority = hit.getPriorityPosition();
384  // (((priority >> 1) & 1) - (priority & 1)) is 0, -1, 1, 0 for priority = 0, 1, 2, 3
385  double relId = hit.getSegmentID() + 0.5 * (((priority >> 1) & 1) - (priority & 1))
386  - m_TSoffset[iSL] - m_idRef[iSL][int(priority < 3)];
387  relId = remainder(relId, (m_TSoffset[iSL + 1] - m_TSoffset[iSL]));
388  return relId;
389 }
390 
391 
392 int
393 NeuroTrigger::getLowestTime(unsigned isector, RelationVector<CDCTriggerSegmentHit> Hits, bool onlyAxials = false)
394 {
395  int tlow = 9999;
396  B2DEBUG(200, "looping over axials:");
397  for (unsigned ihit = 0; ihit < Hits.size(); ++ihit) {
398  // skip hits with negative relation weight (not selected in finder)
399  if (Hits.weight(ihit) < 0) continue;
400  unsigned short iSL = Hits[ihit]->getISuperLayer();
401  if (iSL % 2 == 1 && onlyAxials) {continue;}
402  // get shortest time of relevant hits
403  B2DEBUG(200, " check drifttime: SL" + std::to_string(iSL) + ",ID = " + std::to_string(Hits[ihit]->getSegmentID()) + ", t = " +
404  std::to_string(Hits[ihit]->priorityTime()));
405  double relId = getRelId(*Hits[ihit]);
406  if (m_MLPs[isector].isRelevant(relId, iSL) &&
407  Hits[ihit]->priorityTime() < tlow) {
408  tlow = Hits[ihit]->priorityTime();
409  B2DEBUG(200, " new tlow: " << std::to_string(tlow));
410  }
411  }
412  return tlow;
413 }
414 
415 
416 void
417 NeuroTrigger::getEventTime(unsigned isector, const CDCTriggerTrack& track, std::string et_option, const bool neuroinputmode = false)
418 {
419 
420  if (et_option != m_MLPs[isector].get_et_option()) {
421  B2WARNING("Used event time option is different to the one set in the MLP"
422  << LogVar("et_option", et_option) << LogVar("isector", isector)
423  << LogVar("et_option_mlp", m_MLPs[isector].get_et_option()));
424  }
425  if (et_option == "fastestpriority") {
426  B2DEBUG(200, "et_option is 'fastestpriority'");
427  m_T0 = 9999;
428  // find shortest time of related and relevant axial hits
430  track.getRelationsTo<CDCTriggerSegmentHit>(m_hitCollectionName);
431  m_T0 = getLowestTime(isector, Hits, false);
432  if (m_T0 < 9999) {
433  m_hasT0 = true;
434  } else {
435  m_T0 = 0;
436  m_hasT0 = false;
437  }
438 
439  } else if (et_option == "fastest2d") {
440  m_T0 = 9999;
441  // find shortest time of related and relevant axial hits
443  track.getRelationsTo<CDCTriggerSegmentHit>(m_hitCollectionName);
444  m_T0 = getLowestTime(isector, Hits, true);
445  if (m_T0 < 9999) {
446  m_hasT0 = true;
447  } else {
448  m_T0 = 0;
449  m_hasT0 = false;
450  }
451  } else if (et_option == "zero") {
452  m_hasT0 = true;
453  m_T0 = 0;
454  } else if (et_option == "etf_only") {
455  bool hasT0 = (m_eventTime.isValid()) ? m_eventTime->hasBinnedEventT0(Const::CDC) : false;
456  if (hasT0) {
457  m_T0 = m_eventTime->getBinnedEventT0(Const::CDC);
458  m_hasT0 = true;
459  } else {
460  B2ERROR("No ETF output, but forced to use ETF!");
461  m_hasT0 = false;
462  m_T0 = 0;
463  }
464  } else if (et_option == "etf_or_fastestpriority") {
465  bool hasT0 = (m_eventTime.isValid()) ? m_eventTime->hasBinnedEventT0(Const::CDC) : false;
466  if (hasT0) {
467  m_T0 = m_eventTime->getBinnedEventT0(Const::CDC);
468  m_hasT0 = true;
469  } else {
470  getEventTime(isector, track, "fastestpriority", neuroinputmode);
483  }
484  } else if (et_option == "etf_or_fastest2d") {
485  bool hasT0 = (m_eventTime.isValid()) ? m_eventTime->hasBinnedEventT0(Const::CDC) : false;
486  if (hasT0) {
487  m_T0 = m_eventTime->getBinnedEventT0(Const::CDC);
488  m_hasT0 = true;
489  } else {
490  getEventTime(isector, track, "fastest2d", neuroinputmode);
503  }
504  } else if (et_option == "etf_or_zero") {
505  bool hasT0 = (m_eventTime.isValid()) ? m_eventTime->hasBinnedEventT0(Const::CDC) : false;
506  if (hasT0) {
507  m_T0 = m_eventTime->getBinnedEventT0(Const::CDC);
508  m_hasT0 = true;
509  } else {
510  m_hasT0 = true;
511  m_T0 = 0;
512  }
513  } else if (et_option == "etfcc") {
514  if (!neuroinputmode) {
515  B2ERROR("cannot use 'etfcc' timing option without hw tracks!");
516  } else {
517  if (track.getHasETFTime()) {
518  m_T0 = track.getETF_unpacked();
519  m_hasT0 = true;
520  } else {
521  m_T0 = 0;
522  m_hasT0 = false;
523  }
524  }
525  } else if (et_option == "etfcc_or_zero") {
526  if (!neuroinputmode) {
527  B2ERROR("cannot use 'etfcc' timing option without hw tracks!");
528  } else {
529  if (track.getHasETFTime()) {
530  m_T0 = track.getETF_unpacked();
531  m_hasT0 = true;
532  } else {
533  m_T0 = 0;
534  m_hasT0 = true;
535  }
536  }
537  } else if (et_option == "etfcc_or_fastestpriority") {
538  if (!neuroinputmode) {
539  B2ERROR("cannot use 'etfcc' timing option without hw tracks!");
540  } else {
541  if (track.getHasETFTime()) {
542  m_T0 = track.getETF_unpacked();
543  m_hasT0 = true;
544  } else {
545  getEventTime(isector, track, "fastestpriority", neuroinputmode);
546  }
547  }
548  } else if (et_option == "etfhwin") {
549  if (!neuroinputmode) {
550  B2ERROR("cannot use 'etfcc' timing option without hw tracks!");
551  } else {
552  m_T0 = track.getETF_recalced();
553  m_hasT0 = true;
554  }
555  } else {
556  B2ERROR("No valid parameter for et_option (" << et_option << " )!");
557  }
558 
559 }
560 void
561 NeuroTrigger::getEventTime(unsigned isector, const CDCTriggerTrack& track)
562 {
563  B2WARNING("This function is deprecated, it used the flag 'T0fromHits'. "
564  << "Give additionally et_option as argument to use the new function. "
565  << "et_option is now set for T0fromHits=True to 'etf_fastestpriority' "
566  << "and for T0fromHits=false to 'etf_or_zero'.");
567  if (m_MLPs[isector].getT0fromHits()) {
568  getEventTime(isector, track, "etf_or_fastestpriority");
569  } else {
570  getEventTime(isector, track, "etf_or_zero");
571  }
572 }
573 
574 unsigned long
575 NeuroTrigger::getPureDriftThreshold(unsigned isector, const CDCTriggerTrack& track, const bool neurotrackinputmode)
576 {
577  const CDCTriggerMLP& expert = m_MLPs[isector];
578  unsigned long driftth = 0;
579  vector<unsigned> nHits;
580  nHits.assign(9, 0);
581  // loop over axial hits related to input track
583  track.getRelationsTo<CDCTriggerSegmentHit>(m_hitCollectionName);
584  for (unsigned ihit = 0; ihit < axialHits.size(); ++ ihit) {
585  // skip hits with negative relation weight (not selected in finder)
586  if (axialHits.weight(ihit) < 0) {
587  continue;
588  }
589  unsigned short iSL = axialHits[ihit]->getISuperLayer();
590  // // skip stereo hits (should not be related to track, but check anyway)
591  if ((!neurotrackinputmode) && (iSL % 2 == 1)) continue;
592  // get priority time
593  int t = (m_hasT0) ? axialHits[ihit]->priorityTime() - m_T0 : 0;
594  double relId = getRelId(*axialHits[ihit]);
595  if (t < 0 || t > expert.getTMax()) {
596  if (expert.isRelevant(relId, iSL)) {
597  if (nHits[iSL] < expert.getMaxHitsPerSL()) {
598  driftth |= 1 << (8 - iSL + 9 * nHits[iSL]);
599  ++nHits[iSL];
600  }
601  }
602  }
603  }
604  if (!neurotrackinputmode) {
605  // loop over stereo hits
606  for (int ihit = 0; ihit < m_segmentHits.getEntries(); ++ ihit) {
607  unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
608  // skip axial hits
609  if (iSL % 2 == 0) continue;
610  // get priority time
611  int t = (m_hasT0) ? m_segmentHits[ihit]->priorityTime() - m_T0 : 0;
612  double relId = getRelId(*m_segmentHits[ihit]);
613  if (t < 0 || t > expert.getTMax()) {
614  if (expert.isRelevant(relId, iSL)) {
615  if (nHits[iSL] < expert.getMaxHitsPerSL()) {
616  driftth |= 1 << (8 - iSL + 9 * nHits[iSL]);
617  ++nHits[iSL];
618  }
619  }
620  }
621  }
622  }
623  return driftth;
624 }
625 unsigned long NeuroTrigger::getCompleteHitPattern(unsigned isector, const CDCTriggerTrack& track, const bool neurotrackinputmode)
626 {
627  const CDCTriggerMLP& expert = m_MLPs[isector];
628  unsigned long chitPattern = 0;
629  vector<unsigned> nHits;
630  nHits.assign(9, 0);
631  // loop over axial hits related to input track
633  track.getRelationsTo<CDCTriggerSegmentHit>(m_hitCollectionName);
634  for (unsigned ihit = 0; ihit < axialHits.size(); ++ ihit) {
635  // skip hits with negative relation weight (not selected in finder)
636  if (axialHits.weight(ihit) < 0) {
637  continue;
638  }
639  unsigned short iSL = axialHits[ihit]->getISuperLayer();
640  // // skip stereo hits (should not be related to track, but check anyway)
641  if ((!neurotrackinputmode) && (iSL % 2 == 1)) continue;
642  double relId = getRelId(*axialHits[ihit]);
643  if (expert.isRelevant(relId, iSL)) {
644  if (nHits[iSL] < expert.getMaxHitsPerSL()) {
645  chitPattern |= 1 << (iSL + 9 * nHits[iSL]);
646  ++nHits[iSL];
647  }
648  }
649  }
650  if (!neurotrackinputmode) {
651  // loop over stereo hits
652  for (int ihit = 0; ihit < m_segmentHits.getEntries(); ++ ihit) {
653  unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
654  // skip axial hits
655  if (iSL % 2 == 0) continue;
656  // get priority time
657  double relId = getRelId(*m_segmentHits[ihit]);
658  if (expert.isRelevant(relId, iSL)) {
659  if (nHits[iSL] < expert.getMaxHitsPerSL()) {
660  chitPattern |= 1 << (iSL + 9 * nHits[iSL]);
661  ++nHits[iSL];
662  }
663  }
664  }
665  }
666  return chitPattern;
667 }
668 
669 unsigned long
670 NeuroTrigger::getInputPattern(unsigned isector, const CDCTriggerTrack& track, const bool neurotrackinputmode)
671 {
672  const CDCTriggerMLP& expert = m_MLPs[isector];
673  unsigned long hitPattern = 0;
674  vector<unsigned> nHits;
675  nHits.assign(9, 0);
676  // loop over axial hits related to input track
678  track.getRelationsTo<CDCTriggerSegmentHit>(m_hitCollectionName);
679  for (unsigned ihit = 0; ihit < axialHits.size(); ++ ihit) {
680  // skip hits with negative relation weight (not selected in finder)
681  if (axialHits.weight(ihit) < 0) {
682  continue;
683  }
684  unsigned short iSL = axialHits[ihit]->getISuperLayer();
685  // // skip stereo hits (should not be related to track, but check anyway)
686  if ((!neurotrackinputmode) && (iSL % 2 == 1)) continue;
687  // get priority time
688  int t = (m_hasT0) ? axialHits[ihit]->priorityTime() - m_T0 : 0;
689  if (t < 0) {
690  t = 0;
691  } else if (t > expert.getTMax()) {
692  t = expert.getTMax();
693  }
694  double relId = getRelId(*axialHits[ihit]);
695 
696  if (expert.isRelevant(relId, iSL)) {
697  if (nHits[iSL] < expert.getMaxHitsPerSL()) {
698  hitPattern |= 1 << (iSL + 9 * nHits[iSL]);
699  ++nHits[iSL];
700  }
701  B2DEBUG(250, "hit in SL " << iSL);
702  } else {
703  B2DEBUG(250, "hit in SL " << iSL << " not relevant (relId = " << relId << ")");
704  }
705  }
706  if (!neurotrackinputmode) {
707  // loop over stereo hits
708  for (int ihit = 0; ihit < m_segmentHits.getEntries(); ++ ihit) {
709  unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
710  // skip axial hits
711  if (iSL % 2 == 0) continue;
712  // get priority time
713  int t = (m_hasT0) ? m_segmentHits[ihit]->priorityTime() - m_T0 : 0;
714  if (t < 0) {
715  t = 0;
716  } else if (t > expert.getTMax()) {
717  t = expert.getTMax();
718  }
719  double relId = getRelId(*m_segmentHits[ihit]);
720  if (expert.isRelevant(relId, iSL)) {
721  if (nHits[iSL] < expert.getMaxHitsPerSL()) {
722  hitPattern |= 1 << (iSL + 9 * nHits[iSL]);
723  ++nHits[iSL];
724  }
725  B2DEBUG(250, "hit in SL " << iSL);
726  } else {
727  B2DEBUG(250, "hit in SL " << iSL << " not relevant (relId = " << relId << ")");
728  }
729  }
730  }
731  B2DEBUG(250, "hitPattern " << hitPattern);
732  return hitPattern & expert.getSLpatternMask();
733 }
734 
735 vector<unsigned>
736 NeuroTrigger::selectHitsHWSim(unsigned isector, const CDCTriggerTrack& track)
737 {
738  const CDCTriggerMLP& expert = m_MLPs[isector];
739  vector<unsigned> selectedHitIds = {};
740  // prepare vectors to keep best drift times, left/right and selected hit IDs
741  vector<int> tMin;
742  tMin.assign(expert.nNodesLayer(0), expert.getTMax());
743  vector<bool> LRknown;
744  LRknown.assign(expert.nNodesLayer(0), false);
745  vector<int> hitIds;
746  hitIds.assign(expert.nNodesLayer(0), -1);
747  vector<unsigned> nHits;
748  nHits.assign(9, 0);
749 
750  // loop over all hits related to input track
752  track.getRelationsTo<CDCTriggerSegmentHit>(m_hitCollectionName);
753  B2DEBUG(250, "start hit loop over all related hits");
758  for (unsigned ihit = 0; ihit < allHits.size(); ++ihit) {
759  // skip hits with negative relation weight (not selected in finder)
760  if (allHits.weight(ihit) < 0) continue;
761  unsigned short iSL = allHits[ihit]->getISuperLayer();
762  if (expert.getSLpatternUnmasked() != 0 &&
763  !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
764  B2DEBUG(250, "skipping hit in SL " << iSL);
765  continue;
766  }
767  // get priority time and apply time window cut
768  int t = (m_hasT0) ? allHits[ihit]->priorityTime() - m_T0 : 0;
769  if (t < 0) {
770  t = 0;
771  } else if (t > expert.getTMax()) {
772  t = expert.getTMax();
773  }
774  double relId = getRelId(*allHits[ihit]);
775  if (expert.isRelevant(relId, iSL)) {
776  // get reference hit (worst of existing hits)
777  unsigned short iRef = iSL;
778  if (expert.getMaxHitsPerSL() > 1) {
779  if (nHits[iSL] < expert.getMaxHitsPerSL() &&
780  (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
781  iRef += 9 * nHits[iSL];
782  ++nHits[iSL];
783  } else {
784  for (unsigned compare = iSL; compare < iSL + 9 * nHits[iSL]; compare += 9) {
785  if ((LRknown[iRef] && !LRknown[compare]) ||
786  (LRknown[iRef] == LRknown[compare] && tMin[iRef] < tMin[compare]))
787  iRef = compare;
788  }
789  }
790  }
791  // choose best hit (LR known before LR unknown, then shortest drift time)
792  bool useHit = false;
793  if (LRknown[iRef]) {
794  useHit = (allHits[ihit]->LRknown() && t <= tMin[iRef]);
795  } else {
796  useHit = (allHits[ihit]->LRknown() || t <= tMin[iRef]);
797  }
798  B2DEBUG(250, "relevant wire SL " << iSL << " LR " << allHits[ihit]->getLeftRight()
799  << " t " << t << " iRef " << iRef << " useHit " << useHit);
800  if (useHit) {
801  // keep drift time and LR
802  LRknown[iRef] = allHits[ihit]->LRknown();
803  tMin[iRef] = t;
804  hitIds[iRef] = allHits[ihit]->getArrayIndex();
805  }
806  }
807  }
808  // save selected hit Ids
809  for (unsigned iHit = 0; iHit < hitIds.size(); ++iHit) {
810  if (hitIds[iHit] >= 0) selectedHitIds.push_back(hitIds[iHit]);
811  }
812  return selectedHitIds;
813 }
814 vector<unsigned>
815 NeuroTrigger::selectHits(unsigned isector, const CDCTriggerTrack& track,
816  bool returnAllRelevant)
817 {
818  const CDCTriggerMLP& expert = m_MLPs[isector];
819  vector<unsigned> selectedHitIds = {};
820  // prepare vectors to keep best drift times, left/right and selected hit IDs
821  vector<int> tMin;
822  tMin.assign(expert.nNodesLayer(0), expert.getTMax());
823  vector<bool> LRknown;
824  LRknown.assign(expert.nNodesLayer(0), false);
825  vector<int> hitIds;
826  hitIds.assign(expert.nNodesLayer(0), -1);
827  vector<unsigned> nHits;
828  nHits.assign(9, 0);
829 
830  // loop over axial hits related to input track
832  track.getRelationsTo<CDCTriggerSegmentHit>(m_hitCollectionName);
833  B2DEBUG(250, "start axial hit loop");
834  for (unsigned ihit = 0; ihit < axialHits.size(); ++ihit) {
835  // skip hits with negative relation weight (not selected in finder)
836  if (axialHits.weight(ihit) < 0) continue;
837  unsigned short iSL = axialHits[ihit]->getISuperLayer();
838  // skip stereo hits (should not be related to track, but check anyway)
839  if (iSL % 2 == 1) continue;
840  if (expert.getSLpatternUnmasked() != 0 &&
841  !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
842  B2DEBUG(250, "skipping hit in SL " << iSL);
843  continue;
844  }
845  // get priority time and apply time window cut
846 
847  int t = (m_hasT0) ? axialHits[ihit]->priorityTime() - m_T0 : 0;
848  if (t < 0) {
849  t = 0;
850  } else if (t > expert.getTMax()) {
851  t = expert.getTMax();
852  }
853  double relId = getRelId(*axialHits[ihit]);
854  if (expert.isRelevant(relId, iSL)) {
855  // get reference hit (worst of existing hits)
856  unsigned short iRef = iSL;
857  if (expert.getMaxHitsPerSL() > 1) {
858  if (nHits[iSL] < expert.getMaxHitsPerSL() &&
859  (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
860  iRef += 9 * nHits[iSL];
861  ++nHits[iSL];
862  } else {
863  for (unsigned compare = iSL; compare < iSL + 9 * nHits[iSL]; compare += 9) {
864  if ((LRknown[iRef] && !LRknown[compare]) ||
865  (LRknown[iRef] == LRknown[compare] && tMin[iRef] < tMin[compare]))
866  iRef = compare;
867  }
868  }
869  }
870  // choose best hit (LR known before LR unknown, then shortest drift time)
871  bool useHit = false;
872  if (LRknown[iRef]) {
873  useHit = (axialHits[ihit]->LRknown() && t <= tMin[iRef]);
874  } else {
875  useHit = (axialHits[ihit]->LRknown() || t <= tMin[iRef]);
876  }
877  B2DEBUG(250, "relevant wire SL " << iSL << " LR " << axialHits[ihit]->getLeftRight()
878  << " t " << t << " iRef " << iRef << " useHit " << useHit);
879  if (useHit) {
880  // keep drift time and LR
881  LRknown[iRef] = axialHits[ihit]->LRknown();
882  tMin[iRef] = t;
883  hitIds[iRef] = axialHits[ihit]->getArrayIndex();
884  }
885  if (returnAllRelevant) selectedHitIds.push_back(axialHits[ihit]->getArrayIndex());
886  }
887  }
888 
889  // loop over stereo hits, choosing up to MaxHitsPerSL per superlayer
890  B2DEBUG(250, "start stereo hit loop");
891  for (int ihit = 0; ihit < m_segmentHits.getEntries(); ++ ihit) {
892  unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
893  // skip axial hits
894  if (iSL % 2 == 0) continue;
895  if (expert.getSLpatternUnmasked() != 0 &&
896  !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
897  B2DEBUG(250, "skipping hit in SL " << iSL);
898  continue;
899  }
900  // get priority time and apply time window cut
901  int t = (m_hasT0) ? m_segmentHits[ihit]->priorityTime() - m_T0 : 0;
902  if (t < 0) {
903  t = 0;
904  } else if (t > expert.getTMax()) {
905  t = expert.getTMax();
906  }
907  double relId = getRelId(*m_segmentHits[ihit]);
908  if (expert.isRelevant(relId, iSL)) {
909  // get reference hit (worst of existing hits)
910  unsigned short iRef = iSL;
911  if (expert.getMaxHitsPerSL() > 1) {
912  if (nHits[iSL] < expert.getMaxHitsPerSL() &&
913  (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
914  iRef += 9 * nHits[iSL];
915  ++nHits[iSL];
916  } else {
917  for (unsigned compare = iSL; compare < iSL + 9 * nHits[iSL]; compare += 9) {
918  if ((LRknown[iRef] && !LRknown[compare]) ||
919  (LRknown[iRef] == LRknown[compare] && tMin[iRef] < tMin[compare]))
920  iRef = compare;
921  }
922  }
923  }
924  // choose best hit (LR known before LR unknown, then shortest drift time)
925  bool useHit = false;
926  if (LRknown[iRef]) {
927  useHit = (m_segmentHits[ihit]->LRknown() && t <= tMin[iRef]);
928  } else {
929  useHit = (m_segmentHits[ihit]->LRknown() || t <= tMin[iRef]);
930  }
931  B2DEBUG(250, "relevant wire SL " << iSL << " LR " << m_segmentHits[ihit]->getLeftRight()
932  << " t " << t << " iRef " << iRef << " useHit " << useHit);
933  if (useHit) {
934  // keep drift time and LR
935  LRknown[iRef] = m_segmentHits[ihit]->LRknown();
936  tMin[iRef] = t;
937  hitIds[iRef] = ihit;
938  }
939  if (returnAllRelevant) selectedHitIds.push_back(ihit);
940  }
941  }
942 
943  // save selected hit Ids
944  if (!returnAllRelevant) {
945  for (unsigned iHit = 0; iHit < hitIds.size(); ++iHit) {
946  if (hitIds[iHit] >= 0) selectedHitIds.push_back(hitIds[iHit]);
947  }
948  }
949  return selectedHitIds;
950 }
951 
952 vector<float>
953 NeuroTrigger::getInputVector(unsigned isector, const vector<unsigned>& hitIds)
954 {
955  const CDCTriggerMLP& expert = m_MLPs[isector];
956  // prepare empty input vector and vectors to keep best drift times
957  vector<float> inputVector;
958  inputVector.assign(expert.nNodesLayer(0), 0.);
959  // convert hits to input values
960  vector<unsigned> nHits;
961  nHits.assign(9, 0);
962  for (unsigned ii = 0; ii < hitIds.size(); ++ii) {
963  int ihit = hitIds[ii];
964  unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
965  unsigned short iRef = iSL + 9 * nHits[iSL];
966  ++nHits[iSL];
967  int priot = m_segmentHits[ihit]->priorityTime();
968  int t = (m_hasT0) ? priot - m_T0 : 0;
969  if (t < 0) {
970  t = expert.getTMax();
971  } else if (t > expert.getTMax()) {
972  t = expert.getTMax();
973  }
974  int LR = m_segmentHits[ihit]->getLeftRight();
975  double relId = getRelId(*m_segmentHits[ihit]);
976  int priority = m_segmentHits[ihit]->getPriorityPosition();
977  // get scaled input values (scaling such that the absolute value of all inputs is < 1)
978  inputVector[3 * iRef] = expert.scaleId(relId, iSL);
979  float scaleT = pow(2, floor(log2(1. / expert.getTMax())));
980  inputVector[3 * iRef + 1] = (((LR >> 1) & 1) - (LR & 1)) * t * scaleT;
981  inputVector[3 * iRef + 2] = m_alpha[iSL][int(priority < 3)] * 0.5;
982  }
983  return inputVector;
984 }
985 
986 vector<float>
987 NeuroTrigger::runMLP(unsigned isector, const vector<float>& input)
988 {
989  const CDCTriggerMLP& expert = m_MLPs[isector];
990  vector<float> weights = expert.getWeights();
991  vector<float> layerinput = input;
992  vector<float> layeroutput = {};
993  unsigned iw = 0;
994  for (unsigned il = 1; il < expert.nLayers(); ++il) {
995  //add bias input
996  layerinput.push_back(1.);
997  //prepare output
998  layeroutput.clear();
999  layeroutput.assign(expert.nNodesLayer(il), 0.);
1000  //loop over outputs
1001  for (unsigned io = 0; io < layeroutput.size(); ++io) {
1002  //loop over inputs
1003  for (unsigned ii = 0; ii < layerinput.size(); ++ii) {
1004  layeroutput[io] += layerinput[ii] * weights[iw++];
1005  }
1006  //apply activation function
1007  layeroutput[io] = tanh(layeroutput[io] / 2.);
1008  }
1009  //output is new input
1010  layerinput = layeroutput;
1011  }
1012  return expert.unscaleTarget(layeroutput);
1013 }
1014 
1015 vector<float>
1016 NeuroTrigger::runMLPFix(unsigned isector, vector<float> input)
1017 {
1018  unsigned precisionInput = m_precision[3];
1019  unsigned precisionWeights = m_precision[4];
1020  unsigned precisionLUT = m_precision[5];
1021  unsigned precisionTanh = m_precision[3];
1022  unsigned dp = precisionInput + precisionWeights - precisionLUT;
1023 
1024  const CDCTriggerMLP& expert = m_MLPs[isector];
1025  // transform inputs to fixed point (cut off to input precision)
1026  vector<long> inputFix(input.size(), 0);
1027  for (unsigned ii = 0; ii < input.size(); ++ii) {
1028  inputFix[ii] = long(input[ii] * (1 << precisionInput));
1029  }
1030  // transform weights to fixed point (round to weight precision)
1031  vector<float> weights = expert.getWeights();
1032  vector<long> weightsFix(weights.size(), 0);
1033  for (unsigned iw = 0; iw < weights.size(); ++iw) {
1034  weightsFix[iw] = long(round(weights[iw] * (1 << precisionWeights)));
1035  }
1036  // maximum input value for the tanh LUT
1037  unsigned xMax = unsigned(ceil(atanh(1. - 1. / (1 << (precisionTanh + 1))) *
1038  (1 << (precisionLUT + 1))));
1039 
1040  // run MLP
1041  vector<long> layerinput = inputFix;
1042  vector<long> layeroutput = {};
1043  unsigned iw = 0;
1044  for (unsigned il = 1; il < expert.nLayers(); ++il) {
1045  // add bias input
1046  layerinput.push_back(1 << precisionInput);
1047  // prepare output
1048  layeroutput.clear();
1049  layeroutput.assign(expert.nNodesLayer(il), 0);
1050  // loop over outputs
1051  for (unsigned io = 0; io < layeroutput.size(); ++io) {
1052  // loop over inputs
1053  for (unsigned ii = 0; ii < layerinput.size(); ++ii) {
1054  layeroutput[io] += layerinput[ii] * weightsFix[iw++];
1055  }
1056  // apply activation function -> LUT, calculated on the fly here
1057  unsigned long bin = abs(layeroutput[io]) >> dp;
1058  // correction to get symmetrical rounding errors
1059  float x = (bin + 0.5 - 1. / (1 << (dp + 1))) / (1 << precisionLUT);
1060  long tanhLUT = (bin < xMax) ? long(round(tanh(x / 2.) * (1 << precisionTanh))) : (1 << precisionTanh);
1061  layeroutput[io] = (layeroutput[io] < 0) ? -tanhLUT : tanhLUT;
1062  }
1063  // output is new input
1064  layerinput = layeroutput;
1065  }
1066 
1067  // transform output back to float before unscaling
1068  vector<float> output(layeroutput.size(), 0.);
1069  for (unsigned io = 0; io < output.size(); ++io) {
1070  output[io] = layeroutput[io] / float(1 << precisionTanh);
1071  }
1072  return expert.unscaleTarget(output);
1073 }
1074 
1075 void
1076 NeuroTrigger::save(const string& filename, const string& arrayname)
1077 {
1078  B2INFO("Saving networks to file " << filename << ", array " << arrayname);
1079  TFile datafile(filename.c_str(), "UPDATE");
1080  TObjArray* MLPs = new TObjArray(m_MLPs.size());
1081  for (unsigned isector = 0; isector < m_MLPs.size(); ++isector) {
1082  MLPs->Add(&m_MLPs[isector]);
1083  }
1084  MLPs->Write(arrayname.c_str(), TObject::kSingleKey | TObject::kOverwrite);
1085  datafile.Close();
1086  MLPs->Clear();
1087  delete MLPs;
1088 }
1089 
1090 bool
1091 NeuroTrigger::load(const string& filename, const string& arrayname)
1092 {
1093  if (filename.size() < 1) {
1094  m_MLPs.clear();
1095  m_MLPs = m_cdctriggerneuroconfig->getMLPs();
1096  if (m_MLPs.size() == 0) {
1097  B2ERROR("Could not load Neurotrigger weights from database!");
1098  return false;
1099  }
1100  B2DEBUG(2, "Loaded Neurotrigger MLP weights from database: " + m_cdctriggerneuroconfig->getNNName());
1101  B2DEBUG(100, "loaded " << m_MLPs.size() << " networks from database");
1102  // load some values from the geometry that will be needed for the input
1103  setConstants();
1104  return true;
1105  } else {
1106  TFile datafile(filename.c_str(), "READ");
1107  if (!datafile.IsOpen()) {
1108  B2WARNING("Could not open file " << filename);
1109  return false;
1110  }
1111 
1112  TObjArray* MLPs = (TObjArray*)datafile.Get(arrayname.c_str());
1113  if (!MLPs) {
1114  datafile.Close();
1115  B2WARNING("File " << filename << " does not contain key " << arrayname);
1116  return false;
1117  }
1118  m_MLPs.clear();
1119  for (int isector = 0; isector < MLPs->GetEntriesFast(); ++isector) {
1120  CDCTriggerMLP* expert = dynamic_cast<CDCTriggerMLP*>(MLPs->At(isector));
1121  if (expert) m_MLPs.push_back(*expert);
1122  else B2WARNING("Wrong type " << MLPs->At(isector)->ClassName() << ", ignoring this entry.");
1123  }
1124  MLPs->Clear();
1125  delete MLPs;
1126  datafile.Close();
1127  B2DEBUG(100, "loaded " << m_MLPs.size() << " networks");
1128 
1129  // load some values from the geometry that will be needed for the input
1130  setConstants();
1131 
1132  return true;
1133  }
1134 }
Class to keep all parameters of an expert MLP for the neuro trigger.
Definition: CDCTriggerMLP.h:20
Combination of several CDCHits to a track segment hit for the trigger.
Track created by the CDC trigger.
The Class for CDC Geometry Parameters.
static CDCGeometryPar & Instance(const CDCGeometry *=nullptr)
Static method to get a reference to the CDCGeometryPar instance.
unsigned long getPureDriftThreshold(unsigned isector, const CDCTriggerTrack &track, const bool neurotrackinputmode)
Get the drift threshold bits, where the time of the TS was outside of the accepted time window and th...
double getRelId(const CDCTriggerSegmentHit &hit)
Calculate phi position of a hit relative to 2D track (scaled to number of wires).
void initialize(const Parameters &p)
Set parameters and get some network independent parameters.
Definition: NeuroTrigger.cc:28
std::vector< int > selectMLPs(float phi0, float invpt, float theta)
Select all matching expert MLPs based on the given track parameters.
void updateTrack(const CDCTriggerTrack &track)
Calculate 2D phi position and arclength for the given track and store them.
bool load(const std::string &filename, const std::string &arrayname="MLPs")
Load MLPs from file.
std::vector< unsigned > selectHits(unsigned isector, const CDCTriggerTrack &track, bool returnAllRelevant=false)
Select best hits for each super layer.
std::vector< float > runMLPFix(unsigned isector, std::vector< float > input)
Run an expert MLP with fixed point arithmetic.
void initializeCollections(std::string hitCollectionName, std::string eventTimeName, const std::string &et_option)
set the hit collection and event time to required and store the hit collection name
std::vector< float > getInputVector(unsigned isector, const std::vector< unsigned > &hitIds)
Calculate input values for MLP.
int selectMLPbyPattern(std::vector< int > &MLPs, unsigned long pattern, const bool neurotrackinputmode)
Select one MLP from a list of sector indices.
unsigned long getInputPattern(unsigned isector, const CDCTriggerTrack &track, const bool neurotrackinputmode)
Calculate input pattern for MLP.
void save(const std::string &filename, const std::string &arrayname="MLPs")
Save MLPs to file.
void updateTrackFix(const CDCTriggerTrack &track)
Calculate 2D phi position and arclength for the given track and store them.
std::vector< unsigned > selectHitsHWSim(unsigned isector, const CDCTriggerTrack &track)
Select hits for each super layer from the ones related to input track.
void setConstants()
Loads parameters from the geometry and precalculates some constants that will be needed.
std::vector< unsigned > getRangeIndices(const Parameters &p, unsigned isector)
Get indices for sector ranges in parameter lists.
unsigned long getCompleteHitPattern(unsigned isector, const CDCTriggerTrack &track, const bool neurotrackinputmode)
Get complete hit pattern of neurotrack.
void getEventTime(unsigned isector, const CDCTriggerTrack &track, std::string et_option, const bool)
Read out the event time and store it.
int getLowestTime(unsigned isector, RelationVector< CDCTriggerSegmentHit > Hits, bool onlyAxials)
helper function to get the fastest priority time of given ts array
std::vector< float > runMLP(unsigned isector, const std::vector< float > &input)
Run an expert MLP.
Class for type safe access to objects that are referred to in relations.
size_t size() const
Get number of relations.
float weight(int index) const
Get weight with index.
static const double deg
degree to radians
Definition: Unit.h:109
Class to store variables with their name which were sent to the logging service.
Abstract base class for different kinds of events.
Struct to keep neurotrigger parameters.
Definition: NeuroTrigger.h:45