Belle II Software  release-06-00-14
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'.",
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<bool> tsvector;
186  for (int k = 0; k < 9; k++) {
187  tsvector.push_back(bool ((chitPattern & (1 << k)) >> k));
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 (tphi > -1 * M_PI_4 && tphi < 1 * M_PI_4) { quadrant = 0; }
198  else if (tphi > 1 * M_PI_4 && tphi < 3 * M_PI_4) { quadrant = 1; }
199  else if (tphi > 3 * M_PI_4 || tphi < -3 * M_PI_4) { quadrant = 2; }
200  else if (tphi > -3 * M_PI_4 && tphi < -1 * M_PI_4) { quadrant = 3; }
201 
202 
203 
204 
205 
206  const CDCTriggerTrack* NNtrack =
207  m_tracksNN.appendNew(m_tracks2D[itrack]->getPhi0(),
208  m_tracks2D[itrack]->getOmega(),
209  m_tracks2D[itrack]->getChi2D(),
210  z, cot, 0.,
211  m_tracks2D[itrack]->getFoundOldTrack(),
212  driftthreshold,
213  valtrack,
214  expert,
215  tsvector,
216  m_tracks2D[itrack]->getTime(),
217  quadrant //quadrant simulated from phi
218  - 1, //quadrant not known in simulation
219  m_tracks2D[itrack]->getQualityVector()
220  );
221  m_tracks2D[itrack]->addRelationTo(NNtrack);
222  if (m_neuroTrackInputMode) {
223  m_tracks2D[itrack]->getRelatedFrom<CDCTriggerTrack>(m_realinputCollectionName)->addRelationTo(NNtrack);
224  }
225  // relations to hits used in MLP
226  for (unsigned i = 0; i < hitIds.size(); ++i) {
227  NNtrack->addRelationTo(m_segmentHits[hitIds[i]]);
228  }
229  if (m_writeMLPinput) {
230  // for fixed point precision, round the inputs before saving
231  if (m_fixedPoint) {
232  for (unsigned ii = 0; ii < MLPinput.size(); ++ii) {
233  MLPinput[ii] = long(MLPinput[ii] * (1 << m_precision[3])) / float(1 << m_precision[3]);
234  }
235  }
236  auto* storeInput = m_mlpInput.appendNew(MLPinput, unsigned(isector));
237  NNtrack->addRelationTo(storeInput);
238  }
239  }
240 }
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.
@ 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.