Belle II Software  release-06-01-15
CDCTriggerNeuroModule.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 "trg/cdc/modules/neurotrigger/CDCTriggerNeuroModule.h"
9 
10 #include <cmath>
11 
12 using namespace Belle2;
13 using namespace std;
14 
15 //this line registers the module with the framework and actually makes it available
16 //in steering files or the the module list (basf2 -m).
17 REG_MODULE(CDCTriggerNeuro)
18 
20 {
21  setDescription(
22  "The NeuroTrigger module of the CDC trigger.\n"
23  "Takes track segments and 2D track estimates as input and estimates\n"
24  "the z-vertex for each track using a neural network.\n"
25  "Requires one or several trained networks stored in a file.\n"
26  );
27  setPropertyFlags(c_ParallelProcessingCertified);
28  // parameters for saving / loading
29  addParam("filename", m_filename,
30  "Name of the files where the NeuroTrigger parameters are saved. "
31  "When left blank, the parameters are loaded from the Conditions "
32  "Database."
33  "(compare NeuroTriggerTrainer).",
34  string(""));
35  addParam("arrayname", m_arrayname,
36  "Name of the TObjArray holding the NeuroTrigger parameters "
37  "(compare NeuroTriggerTrainer).",
38  string("MLPs"));
39  addParam("hitCollectionName", m_hitCollectionName,
40  "Name of the input StoreArray of CDCTriggerSegmentHits.",
41  string(""));
42  addParam("EventTimeName", m_EventTimeName,
43  "Name of the event time object.",
44  string(""));
45  addParam("inputCollectionName", m_inputCollectionName,
46  "Name of the StoreArray holding the 2D input tracks or Neurotracks.",
47  string("TRGCDC2DFinderTracks"));
48  addParam("realinputCollectionName", m_realinputCollectionName,
49  "Name of the StoreArray holding the 2D input tracks in case "
50  "Neurotracks were used for the inputCollectionName.",
51  string("CDCTriggerNNInput2DFinderTracks"));
52  addParam("outputCollectionName", m_outputCollectionName,
53  "Name of the StoreArray holding the output tracks with neural "
54  "network estimates.",
55  string("TRGCDCNeuroTracks"));
56  addParam("fixedPoint", m_fixedPoint,
57  "Switch to turn on fixed point arithmetic for FPGA simulation.",
58  false);
59  addParam("precision", m_precision,
60  "fixed point precision in bit after radix point (for track phi, "
61  "scaling factor, reference id, MLP nodes, MLP weights, "
62  "MLP activation function)", {12, 8, 8, 12, 10, 10});
63  addParam("et_option", m_et_option,
64  "option on how to obtain the event time. When left blank, the value "
65  "is loaded from the Conditions Database. Possibilities are: "
66  "'etf_only', 'fastestpriority', 'zero', 'etf_or_fastestpriority', "
67  "'etf_or_zero', 'etf_or_fastest2d', 'fastest2d', 'etfcc' for the unpacked etf in the corresponding cc, 'etfcc_or_fastestpriority', 'etfcc_or_zero', 'etfhwin' for the recalculated time used in hw input. Last two options are only available for neurotrackinputode.",
68  string(""));
69  addParam("writeMLPinput", m_writeMLPinput,
70  "if true, the MLP input vector will be written to the datastore "
71  "(for DQM)",
72  false);
73  addParam("hardwareCompatibilityMode", m_hardwareCompatibilityMode,
74  "Switch to mimic an apparent bug in the hardware preprocessing",
75  false);
76  addParam("NeuroHWTrackInputMode", m_neuroTrackInputMode,
77  "use Neurotracks instead of 2DTracks as input",
78  false);
79 }
80 
81 
82 void
84 {
85  // Load Values from the conditions Database. The actual MLP-values are loaded
86  // in the Neurotrigger class itself to avoid bigger changes in the code.
87  if (m_et_option.size() < 1) {
88  m_et_option = m_cdctriggerneuroconfig->getUseETF() ? "etf_or_fastestpriority" : "fastestpriority";
89  B2DEBUG(2, "The firmware version of the Neurotrigger boards is: " + m_cdctriggerneuroconfig->getNNTFirmwareVersionID());
90  }
91  if (!m_NeuroTrigger.load(m_filename, m_arrayname))
92  B2ERROR("NeuroTrigger could not be loaded correctly.");
93  if (m_fixedPoint) {
94  m_NeuroTrigger.setPrecision(m_precision);
95  }
96  if (m_et_option == "") {
97  m_et_option = m_NeuroTrigger.get_et_option();
98  }
99  m_tracksNN.registerInDataStore(m_outputCollectionName);
100  m_tracks2D.isRequired(m_inputCollectionName);
101  m_segmentHits.isRequired(m_hitCollectionName);
102  m_NeuroTrigger.initializeCollections(m_hitCollectionName, m_EventTimeName, m_et_option);
103 
104  m_tracks2D.registerRelationTo(m_tracksNN);
105  m_tracks2D.requireRelationTo(m_segmentHits);
106  m_tracksNN.registerRelationTo(m_segmentHits);
107  if (m_neuroTrackInputMode) {
108  m_realtracks2D.isRequired(m_realinputCollectionName);
109  m_realtracks2D.registerRelationTo(m_tracksNN);
110  }
111  if (m_writeMLPinput) {
112  m_mlpInput.registerInDataStore(m_outputCollectionName + "Input");
113  m_tracksNN.registerRelationTo(m_mlpInput, DataStore::c_Event);
114  }
115 }
116 
118 {
119  switch (sl) {
120  case 8: return tsid + 0.12;
121  case 4: return tsid / 2;
122  case 3: return tsid - 0.12;
123  case 1: return (tsid + 0.12) / 2;
124  case 0: return tsid / 4;
125  default: return tsid;
126  }
127 }
128 
129 void
131 {
132  for (int itrack = 0; itrack < m_tracks2D.getEntries(); ++itrack) {
133  // calculate parameters that depend only on track
134  if (m_fixedPoint) {
135  m_NeuroTrigger.updateTrackFix(*m_tracks2D[itrack]);
136  } else {
137  m_NeuroTrigger.updateTrack(*m_tracks2D[itrack]);
138  }
139  // get all MLPs that match the phase space sector
140  vector<int> geoSectors =
141  m_NeuroTrigger.selectMLPs(m_tracks2D[itrack]->getPhi0(),
142  m_tracks2D[itrack]->getKappa(1.5),
143  atan2(1., m_tracks2D[itrack]->getCotTheta()));
144  if (geoSectors.size() == 0) continue;
145  // read out or determine event time
146  m_NeuroTrigger.getEventTime(geoSectors[0], *m_tracks2D[itrack], m_et_option, m_neuroTrackInputMode);
147  // get the hit pattern (depends on phase space sector)
148  unsigned long hitPattern =
149  m_NeuroTrigger.getInputPattern(geoSectors[0], *m_tracks2D[itrack], m_neuroTrackInputMode);
150  // get the complete hit pattern for debug purposes
151  unsigned long chitPattern =
152  m_NeuroTrigger.getCompleteHitPattern(geoSectors[0], *m_tracks2D[itrack], m_neuroTrackInputMode);
153  // get the pure driftthreshold vector
154  unsigned long puredriftth =
155  m_NeuroTrigger.getPureDriftThreshold(geoSectors[0], *m_tracks2D[itrack], m_neuroTrackInputMode);
156  // get the MLP that matches the hit pattern
157  int isector = m_NeuroTrigger.selectMLPbyPattern(geoSectors, hitPattern, m_neuroTrackInputMode);
158  if (isector < 0) continue;
159  // get the input for the MLP
160  vector<unsigned> hitIds;
161  if (m_neuroTrackInputMode) {
162  hitIds = m_NeuroTrigger.selectHitsHWSim(isector, *m_tracks2D[itrack]);
163  } else {
164  hitIds = m_NeuroTrigger.selectHits(isector, *m_tracks2D[itrack]);
165  }
166  vector<float> MLPinput = m_NeuroTrigger.getInputVector(isector, hitIds);
167  if (m_hardwareCompatibilityMode) {
168  for (unsigned isl = 0; isl < 9; isl++) {
169  MLPinput[3 * isl] = hwInputIdShuffle(MLPinput[3 * isl], isl);
170  }
171  }
172  // run the MLP
173  vector<float> target;
174  if (m_fixedPoint) {
175  target = m_NeuroTrigger.runMLPFix(isector, MLPinput);
176  } else {
177  target = m_NeuroTrigger.runMLP(isector, MLPinput);
178  }
179  // create a new track with the MLP output values
180  int zIndex = m_NeuroTrigger[isector].zIndex();
181  double z = (zIndex >= 0) ? target[zIndex] : 0.;
182  int thetaIndex = m_NeuroTrigger[isector].thetaIndex();
183  double cot = (thetaIndex >= 0) ? cos(target[thetaIndex]) / sin(target[thetaIndex]) : 0.;
184  bool valtrack = (m_neuroTrackInputMode) ? m_tracks2D[itrack]->getValidStereoBit() : true;
185  std::vector<unsigned> tsvector(9, 0);
186  for (unsigned i = 0; i < hitIds.size(); ++i) {
187  tsvector[m_segmentHits[hitIds[i]]->getISuperLayer()] = m_segmentHits[hitIds[i]]->getLeftRight();
188  }
189  tsvector = (m_neuroTrackInputMode) ? m_tracks2D[itrack]->getTSVector() : tsvector;
190  std::vector<bool> driftthreshold;
191  for (int k = 8; k >= 0; k--) {
192  driftthreshold.push_back(!tsvector[k] || static_cast<bool>((puredriftth & (1 << k)) >> k));
193  }
194  int expert = (m_neuroTrackInputMode) ? m_tracks2D[itrack]->getExpert() : isector;
195  short quadrant = 0;
196  double tphi = m_tracks2D[itrack]->getPhi0();
197  if (m_neuroTrackInputMode) {
198  quadrant = m_tracks2D[itrack]->getQuadrant();
199  } else {
200  if (tphi > -1 * M_PI_4 && tphi < 1 * M_PI_4) { quadrant = 0; }
201  else if (tphi > 1 * M_PI_4 && tphi < 3 * M_PI_4) { quadrant = 1; }
202  else if (tphi > 3 * M_PI_4 || tphi < -3 * M_PI_4) { quadrant = 2; }
203  else if (tphi > -3 * M_PI_4 && tphi < -1 * M_PI_4) { quadrant = 3; }
204  }
205 
206 
207 
208 
209  CDCTriggerTrack* NNtrack =
210  m_tracksNN.appendNew(m_tracks2D[itrack]->getPhi0(),
211  m_tracks2D[itrack]->getOmega(),
212  m_tracks2D[itrack]->getChi2D(),
213  z, cot, 0.,
214  m_tracks2D[itrack]->getFoundOldTrack(),
215  driftthreshold,
216  valtrack,
217  expert,
218  tsvector,
219  m_tracks2D[itrack]->getTime(),
220  quadrant, //quadrant simulated from phi
221  m_tracks2D[itrack]->getQualityVector()
222  );
223  std::stringstream intomega;
224  std::stringstream intphi;
225  std::stringstream intz;
226  std::stringstream inttheta;
227  intomega << std::fixed << std::setprecision(0) << NNtrack->getOmega() / Const::speedOfLight / 1.5e-4 * 0.3 * 34.;
228  intphi << std::fixed << std::setprecision(0) << (((NNtrack->getPhi0() - M_PI / 2.*NNtrack->getQuadrant()) - M_PI / 4.) * 2 *
229  80 /
230  M_PI);
231  std::vector<float> recalcsw(0.);
232  recalcsw = m_cdctriggerneuroconfig->getMLPs()[0].scaleTarget({static_cast<float>(NNtrack->getZ0()), static_cast<float>(NNtrack->getDirection().Theta())});
233  intz << std::fixed << std::setprecision(0) << recalcsw[0] * 4096;
234  inttheta << std::fixed << std::setprecision(0) << recalcsw[1] * 4096;
235 
236  NNtrack->setRawOmega(std::stoi(intomega.str()));
237  NNtrack->setRawPhi0(std::stoi(intphi.str()));
238  NNtrack->setRawZ(std::stoi(intz.str()));
239  NNtrack->setRawTheta(std::stoi(inttheta.str()));
240 
241  m_tracks2D[itrack]->addRelationTo(NNtrack);
242  if (m_neuroTrackInputMode) {
243  m_tracks2D[itrack]->getRelatedFrom<CDCTriggerTrack>(m_realinputCollectionName)->addRelationTo(NNtrack);
244  }
245  // relations to hits used in MLP
246  for (unsigned i = 0; i < hitIds.size(); ++i) {
247  NNtrack->addRelationTo(m_segmentHits[hitIds[i]]);
248  }
249  if (m_writeMLPinput) {
250  // for fixed point precision, round the inputs before saving
251  if (m_fixedPoint) {
252  for (unsigned ii = 0; ii < MLPinput.size(); ++ii) {
253  MLPinput[ii] = long(MLPinput[ii] * (1 << m_precision[3])) / float(1 << m_precision[3]);
254  }
255  }
256  auto* storeInput = m_mlpInput.appendNew(MLPinput, unsigned(isector));
257  NNtrack->addRelationTo(storeInput);
258  }
259  }
260 }
The neural network module of the CDC trigger.
virtual void initialize() override
Initialize the module.
virtual void event() override
Called once for each event.
float hwInputIdShuffle(float tsid, int sl)
shuffle the input ids in the input vector to match the hardware
Track created by the CDC trigger.
void setRawPhi0(const int phi0)
setter and getter functions for raw track values
short getQuadrant() const
get the quadrant
static const double speedOfLight
[cm/ns]
Definition: Const.h:575
@ c_Event
Different object in each event, all objects/arrays are invalidated after event() function has been ca...
Definition: DataStore.h:59
Base class for Modules.
Definition: Module.h:72
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.