Belle II Software  release-08-01-10
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 {
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  );
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','min_etf_fastestpriority' (take the smaller one), '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  addParam("min4axials", m_min4axials,
80  "require at least 4 axial track segments",
81  true);
82 }
83 
84 
85 void
87 {
88  // Load Values from the conditions Database. The actual MLP-values are loaded
89  // in the Neurotrigger class itself to avoid bigger changes in the code.
90  if (m_et_option.size() < 1) {
91  m_et_option = m_cdctriggerneuroconfig->getUseETF() ? "etf_or_fastestpriority" : "fastestpriority";
92  B2DEBUG(2, "The firmware version of the Neurotrigger boards is: " + m_cdctriggerneuroconfig->getNNTFirmwareVersionID());
93  }
95  B2ERROR("NeuroTrigger could not be loaded correctly.");
96  if (m_fixedPoint) {
98  }
99  if (m_et_option == "") {
101  }
106 
110  if (m_neuroTrackInputMode) {
113  }
114  if (m_writeMLPinput) {
117  }
118 }
119 
121 {
122  switch (sl) {
123  case 8: return tsid + 0.12;
124  case 4: return tsid / 2;
125  case 3: return tsid - 0.12;
126  case 1: return (tsid + 0.12) / 2;
127  case 0: return tsid / 4;
128  default: return tsid;
129  }
130 }
131 
132 void
134 {
135  for (int itrack = 0; itrack < m_tracks2D.getEntries(); ++itrack) {
136  // calculate parameters that depend only on track
137  if (m_fixedPoint) {
139  } else {
141  }
142  // get all MLPs that match the phase space sector
143  vector<int> geoSectors =
144  m_NeuroTrigger.selectMLPs(m_tracks2D[itrack]->getPhi0(),
145  m_tracks2D[itrack]->getKappa(1.5),
146  atan2(1., m_tracks2D[itrack]->getCotTheta()));
147  if (geoSectors.size() == 0) continue;
148  // read out or determine event time
150  // get the hit pattern (depends on phase space sector)
151  unsigned long hitPattern =
153  // get the complete hit pattern
154  unsigned long chitPattern =
156  // check, if enough axials are there. first, we select the axial bits from the
157  // hitpattern (341 = int('101010101',base=2)) and then check if the number of
158  // ones is equal or greater than 4.
159  bool valtrack = (m_neuroTrackInputMode) ? m_tracks2D[itrack]->getValidStereoBit() : true;
160  if ((chitPattern & 341) != 341 && // this is an ugly workaround, because popcount is only
161  (chitPattern & 341) != 340 && // available with c++20 and newer
162  (chitPattern & 341) != 337 &&
163  (chitPattern & 341) != 325 &&
164  (chitPattern & 341) != 277 &&
165  (chitPattern & 341) != 85 &&
166  m_min4axials == true) {
167  B2DEBUG(250, "Not enough axial hits (<4), setting track invalid!");
168  valtrack = false;
169  }
170  // get the pure driftthreshold vector
171  unsigned long puredriftth =
173  // get the MLP that matches the hit pattern
174  int isector = m_NeuroTrigger.selectMLPbyPattern(geoSectors, hitPattern, m_neuroTrackInputMode);
175  if (isector < 0) continue;
176  // get the input for the MLP
177  vector<unsigned> hitIds;
178  if (m_neuroTrackInputMode) {
179  hitIds = m_NeuroTrigger.selectHitsHWSim(isector, *m_tracks2D[itrack]);
180  } else {
181  hitIds = m_NeuroTrigger.selectHits(isector, *m_tracks2D[itrack]);
182  }
183  vector<float> MLPinput = m_NeuroTrigger.getInputVector(isector, hitIds);
185  for (unsigned isl = 0; isl < 9; isl++) {
186  MLPinput[3 * isl] = hwInputIdShuffle(MLPinput[3 * isl], isl);
187  }
188  }
189  // run the MLP
190  vector<float> target;
191  if (m_fixedPoint) {
192  target = m_NeuroTrigger.runMLPFix(isector, MLPinput);
193  } else {
194  target = m_NeuroTrigger.runMLP(isector, MLPinput);
195  }
196  // create a new track with the MLP output values
197  int zIndex = m_NeuroTrigger[isector].zIndex();
198  double z = (zIndex >= 0) ? target[zIndex] : 0.;
199  int thetaIndex = m_NeuroTrigger[isector].thetaIndex();
200  double cot = (thetaIndex >= 0) ? cos(target[thetaIndex]) / sin(target[thetaIndex]) : 0.;
201  std::vector<unsigned> tsvector(9, 0);
202  for (unsigned i = 0; i < hitIds.size(); ++i) {
203  tsvector[m_segmentHits[hitIds[i]]->getISuperLayer()] = m_segmentHits[hitIds[i]]->getLeftRight();
204  }
205  tsvector = (m_neuroTrackInputMode) ? m_tracks2D[itrack]->getTSVector() : tsvector;
206  std::vector<bool> driftthreshold;
207  for (int k = 8; k >= 0; k--) {
208  driftthreshold.push_back(!tsvector[k] || static_cast<bool>((puredriftth & (1 << k)) >> k));
209  }
210  int expert = (m_neuroTrackInputMode) ? m_tracks2D[itrack]->getExpert() : isector;
211  short quadrant = 0;
212  double tphi = m_tracks2D[itrack]->getPhi0();
213  if (m_neuroTrackInputMode) {
214  quadrant = m_tracks2D[itrack]->getQuadrant();
215  } else {
216  if (tphi > -1 * M_PI_4 && tphi < 1 * M_PI_4) { quadrant = 3; }
217  else if (tphi > 1 * M_PI_4 && tphi < 3 * M_PI_4) { quadrant = 0; }
218  else if (tphi > 3 * M_PI_4 || tphi < -3 * M_PI_4) { quadrant = 1; }
219  else if (tphi > -3 * M_PI_4 && tphi < -1 * M_PI_4) { quadrant = 2; }
220  }
221 
222 
223 
224 
225  CDCTriggerTrack* NNtrack =
226  m_tracksNN.appendNew(m_tracks2D[itrack]->getPhi0(),
227  m_tracks2D[itrack]->getOmega(),
228  m_tracks2D[itrack]->getChi2D(),
229  z, cot, 0.,
230  m_tracks2D[itrack]->getFoundOldTrack(),
231  driftthreshold,
232  valtrack,
233  expert,
234  tsvector,
235  m_tracks2D[itrack]->getTime(),
236  quadrant, //quadrant simulated from phi
237  m_tracks2D[itrack]->getQualityVector()
238  );
239  std::stringstream intomega;
240  std::stringstream intphi;
241  std::stringstream intz;
242  std::stringstream inttheta;
243  intomega << std::fixed << std::setprecision(0) << NNtrack->getOmega() / Const::speedOfLight / 1.5e-4 * 0.3 * 34.;
244  intphi << std::fixed << std::setprecision(0) << (((NNtrack->getPhi0() - M_PI / 2.*NNtrack->getQuadrant()) - M_PI / 4.) * 2 *
245  80 /
246  M_PI);
247  std::vector<float> recalcsw(0.);
248  recalcsw = m_cdctriggerneuroconfig->getMLPs()[0].scaleTarget({static_cast<float>(NNtrack->getZ0()), static_cast<float>(NNtrack->getDirection().Theta())});
249  intz << std::fixed << std::setprecision(0) << recalcsw[0] * 4096;
250  inttheta << std::fixed << std::setprecision(0) << recalcsw[1] * 4096;
251 
252  NNtrack->setRawOmega(std::stoi(intomega.str()));
253  NNtrack->setRawPhi0(std::stoi(intphi.str()));
254  NNtrack->setRawZ(std::stoi(intz.str()));
255  NNtrack->setRawTheta(std::stoi(inttheta.str()));
256  NNtrack->setHasETFTime(m_tracks2D[itrack]->getHasETFTime());
257  NNtrack->setETF_unpacked(m_tracks2D[itrack]->getETF_unpacked());
258  NNtrack->setETF_recalced(m_tracks2D[itrack]->getETF_recalced());
259 
260  m_tracks2D[itrack]->addRelationTo(NNtrack);
261  if (m_neuroTrackInputMode) {
262  m_tracks2D[itrack]->getRelatedFrom<CDCTriggerTrack>(m_realinputCollectionName)->addRelationTo(NNtrack);
263  }
264  // relations to hits used in MLP
265  for (unsigned i = 0; i < hitIds.size(); ++i) {
266  NNtrack->addRelationTo(m_segmentHits[hitIds[i]]);
267  }
268  if (m_writeMLPinput) {
269  // for fixed point precision, round the inputs before saving
270  if (m_fixedPoint) {
271  for (unsigned ii = 0; ii < MLPinput.size(); ++ii) {
272  MLPinput[ii] = long(MLPinput[ii] * (1 << m_precision[3])) / float(1 << m_precision[3]);
273  }
274  }
275  auto* storeInput = m_mlpInput.appendNew(MLPinput, unsigned(isector));
276  NNtrack->addRelationTo(storeInput);
277  }
278  }
279 }
std::string m_EventTimeName
name of the event time StoreObjPtr
StoreArray< CDCTriggerTrack > m_tracks2D
list of input 2D tracks or neurotracks
DBObjPtr< CDCTriggerNeuroConfig > m_cdctriggerneuroconfig
get NNT payload from database.
CDCTriggerNeuroModule()
Constructor, for setting module description and parameters.
StoreArray< CDCTriggerTrack > m_realtracks2D
list of input real 2D tracks
StoreArray< CDCTriggerTrack > m_tracksNN
list of output NN tracks
virtual void initialize() override
Initialize the module.
StoreArray< CDCTriggerMLPInput > m_mlpInput
list of input vectors for each NN track
virtual void event() override
Called once for each event.
StoreArray< CDCTriggerSegmentHit > m_segmentHits
list of track segment hits
std::string m_outputCollectionName
Name of the StoreArray containing the resulting NN tracks.
NeuroTrigger m_NeuroTrigger
Instance of the NeuroTrigger.
std::vector< unsigned > m_precision
Fixed point precision in bit after radix point.
std::string m_arrayname
Name of the TObjArray holding the networks.
float hwInputIdShuffle(float tsid, int sl)
shuffle the input ids in the input vector to match the hardware
bool m_neuroTrackInputMode
use Neurotracks as InputTracks
std::string m_inputCollectionName
Name of the StoreArray containing the input 2D tracks or neurotracks.
bool m_fixedPoint
Switch to execute the network with fixed point calculation.
bool m_writeMLPinput
Switch for writing out the input vector for each track (off by default).
std::string m_et_option
way to obtain the event time, possible values are: "etf_only" : only ETF info is used,...
std::string m_realinputCollectionName
Name of the StoreArray containing the real input 2D tracks.
std::string m_filename
Name of file where network weights etc.
bool m_min4axials
require at least 4 axial track segments
std::string m_hitCollectionName
Name of the StoreArray containing the input track segment hits.
bool m_hardwareCompatibilityMode
Switch to mimic an apparent bug in the hardware preprocessing.
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:686
@ 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
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition: Module.cc:208
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition: Module.h:80
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...
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.
std::string get_et_option()
Return value of m_et_option.
Definition: NeuroTrigger.h:229
unsigned long getInputPattern(unsigned isector, const CDCTriggerTrack &track, const bool neurotrackinputmode)
Calculate input pattern for MLP.
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 setPrecision(const std::vector< unsigned > &precision)
set fixed point precision
Definition: NeuroTrigger.h:151
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.
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
bool requireRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, const std::string &namedRelation="") const
Produce error if no relation from this array to 'toArray' has been registered.
Definition: StoreArray.h:155
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:246
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:216
bool registerRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut, const std::string &namedRelation="") const
Register a relation to the given StoreArray.
Definition: StoreArray.h:140
REG_MODULE(arichBtest)
Register the Module.
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:560
Abstract base class for different kinds of events.