Belle II Software development
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
12using namespace Belle2;
13using 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).
17REG_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
85void
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
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
132void
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;
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();
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);
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:695
@ 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
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
#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.
STL namespace.