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