Belle II Software development
NeuroTriggerParameters.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/NeuroTriggerParameters.h>
9
10
11#include <TFile.h>
12#include "boost/iostreams/filter/gzip.hpp"
13#include "boost/iostreams/filtering_streambuf.hpp"
14#include "boost/iostreams/filtering_stream.hpp"
15#include "boost/multi_array.hpp"
16#include <iostream>
17#include <fstream>
18#include <framework/core/Module.h>
19
20
21using namespace Belle2;
22
23NeuroTriggerParameters::NeuroTriggerParameters(std::string& filename)
24{
26
27}
28
29void
30NeuroTriggerParameters::loadconfigtxt(const std::string& filename)
31{
32 // now loading confile
33 std::ifstream confile;
34 try {
35 confile.open(filename, std::ifstream::in);
36 } catch (int e) {
37 saveconfigtxt("neuroconfig_example.conf");
38 B2ERROR("Configuration file " + filename + " could not be loaded! Make sure to give the configuration file as a parameter. \
39 An example file neuroconfig_example.conf has been saved.");
40
41 exit(EXIT_FAILURE);
42 }
43 std::string line_all;
44 if (!confile.is_open()) {
45 saveconfigtxt("neuroconfig_example.conf");
46 B2ERROR("Configuration file " + filename + " could not be loaded! Make sure to give the configuration file as a parameter. \
47 An example file neuroconfig_example.conf has been saved.");
48 exit(EXIT_FAILURE);
49 }
50 while (std::getline(confile, line_all)) {
51 // remove comments
52 std::size_t hashtag = line_all.find('#');
53 std::string line = line_all.substr(0, hashtag);
54 std::string par;
55 std::string key;
56 std::string skip;
57 if (line.length() < 3) {
58 continue;
59 // check, if line wasnt a pure comment line
60 }
61 bool locked = false; //check, if "==" was used and the variable should be registered as locked
62 if (line.find('=') == std::string::npos) {
63 continue;
64 }
65 line.erase(std::remove(line.begin(), line.end(), ' '), line.end()); // remove whitespaces in whole string
66 par = line.substr(0, line.find('='));
67 std::string l;
68 l = line.substr(line.find("=") + 1, 1);
69 if (l == "=") {
70 locked = true;
71 }
72 // now find the value that should be asigned to the "par"
73 key = (locked) ? line.substr((line.find('=') + 2), line.length() - line.find('=') - 2) : line.substr((line.find('=') + 1),
74 line.length() - line.find('=') - 1);
75 if (par == "nInput") {
76 nInput = std::stoul(key);
77 if (locked) {nInput.lock();}
78 } else if (par == "nOutput") {
79 nOutput = std::stoul(key);
80 if (locked) {nOutput.lock();}
81 } else if (par == "relevantCut") {
82 relevantCut = std::stod(key);
83 if (locked) {relevantCut.lock();}
84 } else if (par == "nMLP") {
85 nMLP = std::stoul(key);
86 if (locked) {nMLP.lock();}
87 } else if (par == "targetZ") {
88 targetZ = std::stoi(key);
89 if (locked) {targetZ.lock();}
90 } else if (par == "targetTheta") {
91 targetTheta = std::stoi(key);
92 if (locked) {targetTheta.lock();}
93 } else if (par == "multiplyHidden") {
94 multiplyHidden = std::stoi(key);
95 if (locked) {multiplyHidden.lock();}
96 } else if (par == "rescaleTarget") {
97 rescaleTarget = std::stoi(key);
98 if (locked) {rescaleTarget.lock();}
99 } else if (par == "cutSum") {
100 cutSum = std::stoi(key);
101 if (locked) {cutSum.lock();}
102 } else if (par == "tMax") {
103 tMax = std::stoul(key);
104 if (locked) {tMax.lock();}
105 } else if (par == "ETOption") {
106 ETOption = std::stoul(key);
107 if (locked) {ETOption.lock();}
108 } else if (par == "IDRanges") {
109 IDRanges = read2dArray<float>(key, locked);
110 } else if (par == "phiRangeUse") {
111 phiRangeUse = read2dArray<float>(key, locked);
112 } else if (par == "thetaRangeUse") {
113 thetaRangeUse = read2dArray<float>(key, locked);
114 } else if (par == "invptRangeUse") {
115 invptRangeUse = read2dArray<float>(key, locked);
116 } else if (par == "phiRangeTrain") {
117 phiRangeTrain = read2dArray<float>(key, locked);
118 } else if (par == "thetaRangeTrain") {
119 thetaRangeTrain = read2dArray<float>(key, locked);
120 } else if (par == "invptRangeTrain") {
121 invptRangeTrain = read2dArray<float>(key, locked);
122 } else if (par == "nHidden") {
123 nHidden = read2dArray<float>(key, locked);
124 } else if (par == "maxHitsPerSL") {
125 maxHitsPerSL = read1dArray<unsigned short>(key, locked);
126 } else if (par == "outputScale") {
127 outputScale = read2dArray<float>(key, locked);
128 } else if (par == "SLpattern") {
129 SLpattern = read1dArray<unsigned long>(key, locked);
130 } else if (par == "SLpatternMask") {
131 SLpatternMask = read1dArray<unsigned long>(key, locked);
132 } else if (par == "precision") {
133 precision = read1dArray<unsigned>(key, locked);
134 }
135 }
136}
137template<typename X>
138bool NeuroTriggerParameters::checkarr(std::vector<std::vector<NNTParam<X>>> vec)
139{
140 // check, if a vector is already set. this is done by just checking the first member of the vector.
141 if (vec.size() < 1) {return false;}
142 else if (vec[0].size() < 1) {return false;}
143 else {return vec[0][0].isSet();}
144}
145
146template<typename X>
148{
149 // check, if a vector is already set. this is done by just checking the first member of the vector.
150 if (vec.size() < 1) {return false;}
151 else {return vec[0].isSet();}
152}
153
154void NeuroTriggerParameters::saveconfigtxt(const std::string& filename)
155{
156 // save all the configuration otions in a file, which can later be used to initialize a new parameter set.
157 // only paramters, that already have been set are saved. parameters which are locked, are written wit a "==".
158 std::ofstream savestream;
159 savestream.open(filename);
160 savestream << "########################################################" << std::endl;
161 savestream << "### Neurotrigger configuration file created by basf2 ###" << std::endl;
162 savestream << "########################################################" << std::endl << std::endl;
163 savestream << "# '=' means the parameter is set and can be changed," << std::endl;
164 savestream << "# '==' means the parameter is locked and should not be changed." << std::endl << std::endl;
165
166 savestream << "# number of input nodes " << std::endl;
167 if (nInput.isSet()) {
168 savestream << "nInput " << (nInput.isLocked() ? "== " : "= ") << nInput << std::endl;
169 savestream << std::endl;
170 } else {savestream << "nInput = 27" << std::endl;}
171 savestream << "# number of output nodes " << std::endl;
172 if (nOutput.isSet()) {
173 savestream << "nOutput " << (nOutput.isLocked() ? "== " : "= ") << nOutput << std::endl;
174 savestream << std::endl;
175 } else {savestream << "nOutput = 2" << std::endl;}
176 savestream << "# If true, relevantCut is applied to the sum over hit counters, " << std::endl;
177 savestream << "# otherwise directly on the hit counters." << std::endl;
178 if (cutSum.isSet()) {
179 savestream << "cutSum " << (cutSum.isLocked() ? "== " : "= ") << cutSum << std::endl;
180 savestream << std::endl;
181 } else {savestream << "cutSum = 0" << std::endl;}
182 savestream << "# only used in the idhist module. it defines the how much of the idrange is cut off after making the histogram " <<
183 std::endl;
184 if (relevantCut.isSet()) {
185 savestream << "relevantCut " << (relevantCut.isLocked() ? "== " : "= ") << relevantCut << std::endl;
186 savestream << std::endl;
187 } else {savestream << "relevantCut = 0.02" << std::endl;}
188 savestream << "# flag to allow for target tracks lying out of the output range to be rescaled during training. " << std::endl;
189 if (rescaleTarget.isSet()) {
190 savestream << "rescaleTarget " << (rescaleTarget.isLocked() ? "== " : "= ") << rescaleTarget << std::endl;
191 savestream << std::endl;
192 } else {savestream << "rescaleTarget = 0" << std::endl;}
193 savestream << "# Number of networks. For network specific parameters you can give " << std::endl;
194 savestream << "# either a list with values for each network, or a single value that will be used" << std::endl;
195 savestream << "# for all. The ranges are also valid if nPhi * nPt * nTheta * nPattern = nMLPs. " << std::endl;
196 if (nMLP.isSet()) {
197 savestream << "nMLP " << (nMLP.isLocked() ? "== " : "= ") << nMLP << std::endl;
198 savestream << std::endl;
199 } else {savestream << "nMLP = 5" << std::endl;}
200 savestream << "# train z as output " << std::endl;
201 if (targetZ.isSet()) {
202 savestream << "targetZ " << (targetZ.isLocked() ? "== " : "= ") << targetZ << std::endl;
203 savestream << std::endl;
204 } else {savestream << "targetZ = 1" << std::endl;}
205 savestream << "# train theta as output " << std::endl;
206 if (targetTheta.isSet()) {
207 savestream << "targetTheta " << (targetTheta.isLocked() ? "== " : "= ") << targetTheta << std::endl;
208 savestream << std::endl;
209 } else {savestream << "targetTheta = 1" << std::endl;}
210 savestream << "# If true, multiply nHidden with number of input nodes. " << std::endl;
211 if (multiplyHidden.isSet()) {
212 savestream << "multiplyHidden " << (multiplyHidden.isLocked() ? "== " : "= ") << multiplyHidden << std::endl;
213 savestream << std::endl;
214 } else {savestream << "multiplyHidden = 0" << std::endl;}
215 savestream << "# Maximal drift time, identical for all networks. " << std::endl;
216 if (tMax.isSet()) {
217 savestream << "tMax " << (tMax.isLocked() ? "== " : "= ") << tMax << std::endl;
218 savestream << std::endl;
219 } else {savestream << "tMax = 256" << std::endl;}
220 savestream << "# Determine, how the event time should be obtained. The options are:" << std::endl;
221 for (unsigned i = 0; i < 11; i++) {
222 savestream << "# " << i << ": " << to_strTiming(i) << std::endl;
223 }
224 if (ETOption.isSet()) {
225 savestream << "ETOption " << (ETOption.isLocked() ? "== " : "= ") << ETOption << std::endl;
226 savestream << std::endl;
227 } else {savestream << "ETOption = 7" << std::endl;}
228 savestream << "# Phi region for which MLP is used in degree for all networks. " << std::endl;
229 if (checkarr(phiRangeUse)) {
230 savestream << print2dArray<float>("phiRangeUse", phiRangeUse);
231 savestream << std::endl;
232 } else {savestream << "phiRangeUse = [[0, 360]]" << std::endl;}
233 savestream << "# relative ID range of the relevant wire IDs of the track segments " << std::endl;
234 savestream << "# that are taken into consideration when determining the best fitting track segments. " << std::endl;
235 if (checkarr(IDRanges)) {
236 savestream << print2dArray<float>("IDRanges", IDRanges);
237 savestream << std::endl;
238 } else {
239 savestream << "IDRanges = [[0,-1.5,1.5,-7.5,-0.5,-1.5,1.5,0.5,7.5,-1.5,1.5,-8.5,0.5,-2.5,1.5,-0.5,10.5,-3.5,2.5],";
240 savestream << "[1,-1.5,1.5,-7.5,-0.5,-1.5,1.5,0.5,7.5,-1.5,1.5,-8.5,0.5,-2.5,1.5,-0.5,10.5,-3.5,2.5],";
241 savestream << "[2,-1.5,1.5,-7.5,-0.5,-1.5,1.5,0.5,7.5,-1.5,1.5,-8.5,0.5,-2.5,1.5,-0.5,10.5,-3.5,2.5],";
242 savestream << "[3,-1.5,1.5,-7.5,-0.5,-1.5,1.5,0.5,7.5,-1.5,1.5,-8.5,0.5,-2.5,1.5,-0.5,10.5,-3.5,2.5],";
243 savestream << "[4,-1.5,1.5,-7.5,-0.5,-1.5,1.5,0.5,7.5,-1.5,1.5,-8.5,0.5,-2.5,1.5,-0.5,10.5,-3.5,2.5]]";
244 savestream << std::endl;
245 }
246 savestream << "# Theta region for which MLP is used in degree for all networks. " << std::endl;
247 if (checkarr(thetaRangeUse)) {
248 savestream << print2dArray<float>("thetaRangeUse", thetaRangeUse);
249 savestream << std::endl;
250 } else {savestream << "thetaRangeUse = [[10, 170]]" << std::endl;}
251 savestream << "# Charge / Pt region for which MLP is used in 1/GeV for all networks. " << std::endl;
252 if (checkarr(invptRangeUse)) {
253 savestream << print2dArray<float>("invptRangeUse", invptRangeUse);
254 savestream << std::endl;
255 } else {savestream << "invptRangeUse = [[-5, 5]]" << std::endl;}
256 savestream << "# Phi region for which MLP is trained in degree for all networks. " << std::endl;
257 savestream << "# Can be larger than use range to avoid edge effects. " << std::endl;
258 if (checkarr(phiRangeTrain)) {
259 savestream << print2dArray<float>("phiRangeTrain", phiRangeTrain);
260 savestream << std::endl;
261 } else {savestream << "phiRangeTrain = [[0, 360]]" << std::endl;}
262 savestream << "# Theta region for which MLP is trained in degree for all networks. " << std::endl;
263 savestream << "# Can be larger than use range to avoid edge effects. " << std::endl;
265 savestream << print2dArray<float>("thetaRangeTrain", thetaRangeTrain);
266 savestream << std::endl;
267 } else {savestream << "thetaRangeTrain = [[10, 170]]" << std::endl;}
268 savestream << "# charge/Pt region for which MLP is trained in degree for all networks. " << std::endl;
269 savestream << "# Can be larger than use range to avoid edge effects. " << std::endl;
271 savestream << print2dArray<float>("invptRangeTrain", invptRangeTrain);
272 savestream << std::endl;
273 } else {savestream << "invptRangeTrain = [[-5, 5]]" << std::endl;}
274 savestream << "# Number of nodes in each hidden layer for all networks" << std::endl;
275 savestream << "# or factor to multiply with number of inputs." << std::endl;
276 savestream << "# The number of layers is derived from the shape." << std::endl;
277 if (checkarr(nHidden)) {
278 savestream << print2dArray<float>("nHidden", nHidden);
279 savestream << std::endl;
280 } else {savestream << "nHidden = [[81]]" << std::endl;}
281 savestream << "# Maximum number of hits in a single super layer for all networks. " << std::endl;
282 if (checkarr(maxHitsPerSL)) {
283 savestream << print1dArray<unsigned short>("maxHitsPerSL", maxHitsPerSL);
284 savestream << std::endl;
285 } else {savestream << "maxHitsPerSL = [1]" << std::endl;}
286 savestream << "# Output scale for all networks. " << std::endl;
287 if (checkarr(outputScale)) {
288 savestream << print2dArray<float>("outputScale", outputScale);
289 savestream << std::endl;
290 } else {savestream << "outputScale = [[-100, 100, 10, 170]]" << std::endl;}
291 savestream << "# Super layer pattern for which MLP is trained for all networks." << std::endl;
292 savestream << "# Binary pattern of 9 * maxHitsPerSL bits (on/off for each hit)." << std::endl;
293 savestream << "# 0 in bit <i>: hits from super layer <i> are not used." << std::endl;
294 savestream << "# 1 in bit <i>: hits from super layer <i> are used." << std::endl;
295 savestream << "# SLpattern = 0: use any hits present, don't check the pattern. " << std::endl;
296 if (checkarr(SLpattern)) {
297 savestream << print1dArray<unsigned long>("SLpattern", SLpattern);
298 savestream << std::endl;
299 } else {savestream << "SLpattern = [511, 383, 479, 503, 509]" << std::endl;}
300 savestream << "# Super layer pattern mask for which MLP is trained for all networks." << std::endl;
301 savestream << "# Binary pattern of 9 * maxHitsPerSL bits (on/off for each hit)." << std::endl;
302 savestream << "# 0 in bit <i>: super layer <i> may or may not have a hit." << std::endl;
303 savestream << "# 1 in bit <i>: super layer <i>" << std::endl;
304 savestream << "# - must have a hit if SLpattern bit <i> = 1" << std::endl;
305 savestream << "# - must not have a hit if SLpattenr bit <i> = 0 " << std::endl;
306 if (checkarr(SLpatternMask)) {
307 savestream << print1dArray<unsigned long>("SLpatternMask", SLpatternMask);
308 savestream << std::endl;
309 } else {savestream << "SLpatternMask = [170]" << std::endl;}
310 savestream << "# precision used for the hardware simulation " << std::endl;
311 if (checkarr(precision)) {
312 savestream << print1dArray<unsigned>("precision", precision);
313 savestream << std::endl;
314 } else {savestream << "precision = [12, 8, 8, 12, 10, 10]" << std::endl;}
315 savestream.close();
316}
317
318template<typename X>
319std::string NeuroTriggerParameters::print2dArray(const std::string& name, std::vector<std::vector<NNTParam<X>>> vecvec)
320{
321 // this is a class for piping the output of a 2d array to a string with brackets
322 std::stringstream savestream;
323 savestream << name << " " << (vecvec[0][0].isLocked() ? "== " : "= ") << "[";
324 bool outcomma = false;
325 for (auto x : vecvec) {
326 if (outcomma) {savestream << ",";}
327 outcomma = true;
328 savestream << "[";
329 bool incomma = false;
330 for (auto y : x) {
331 if (incomma) {savestream << ",";}
332 incomma = true;
333 savestream << y;
334 }
335 savestream << "]";
336 }
337 savestream << "]" << std::endl;
338 return savestream.str();
339}
340template<typename X>
341std::string NeuroTriggerParameters::print1dArray(const std::string& name, std::vector<NNTParam<X>> vecvec)
342{
343 // this is a class for piping the output of a 1d array to a string with brackets
344 std::stringstream savestream;
345 savestream << name << " " << (vecvec[0].isLocked() ? "== " : "= ") << "[";
346 bool incomma = false;
347 for (auto y : vecvec) {
348 if (incomma) {savestream << ",";}
349 incomma = true;
350 savestream << y;
351 }
352 savestream << "]" << std::endl;
353 return savestream.str();
354}
355template<typename X>
356std::vector<std::vector<NNTParam<X>>> NeuroTriggerParameters::read2dArray(std::string keyx, bool locked)
357{
358 std::vector<std::vector<NNTParam<X>>> retarr;
359 std::string key = keyx;
360 // parse the brackets here to fill the vector: [[1,2], 3,4]]
361 key = key.substr(key.find("[") + 1, std::string::npos); // without outer brackets: [1,2], [3,4]
362 for (std::size_t ipos = 0; ipos != std::string::npos; ipos = key.find("[", ipos + 1)) {
363 std::string pairstr = key.substr(ipos + 1, key.find("]", ipos + 1) - ipos - 1); // this shopuld be 1,2 now
364 std::vector<NNTParam<X>> newpair;
365 std::size_t jpos;
366 for (jpos = 0; jpos != std::string::npos; jpos = pairstr.find(",", jpos)) {
367 if (!(jpos == 0)) {jpos++;}
368 newpair.push_back(NNTParam<X>(std::stof(pairstr.substr(jpos, pairstr.find(",") - jpos))));
369 if (locked) {newpair.back().lock();}
370 }
371 retarr.push_back(newpair);
372 }
373 return retarr;
374}
375
376template<typename X>
377std::vector<NNTParam<X>> NeuroTriggerParameters::read1dArray(std::string keyx, bool locked)
378{
379 std::string key = keyx;
380 // parse the brackets here to fill the vector: [[1,2], 3,4]]
381 std::string pairstr = key.substr(1, key.find("]", 1) - 1); // this shopuld be 1,2 now
382 std::vector<NNTParam<X>> newpair;
383 std::size_t jpos;
384 for (jpos = 0; jpos != std::string::npos; jpos = pairstr.find(",", jpos)) {
385 if (!(jpos == 0)) {jpos++;}
386 newpair.push_back(NNTParam<X>(std::stof(pairstr.substr(jpos, pairstr.find(",") - jpos))));
387 if (locked) {newpair.back().lock();}
388 }
389 return newpair;
390}
Class to represent a complete set to describe a Neurotrigger.
bool isLocked() const
check, if variable was already locked and is read only now
bool isSet() const
check, if variable was already initialized
void lock()
lock the variable, to make it read only
std::vector< NNTParam< unsigned short > > maxHitsPerSL
Maximum number of hits in a single super layer for all networks.
std::vector< std::vector< NNTParam< float > > > invptRangeUse
Charge / Pt region for which MLP is used in 1/GeV for all networks.
std::vector< std::vector< NNTParam< float > > > thetaRangeUse
Theta region for which MLP is used in degree for all networks.
NNTParam< unsigned > nMLP
Number of networks.
std::vector< NNTParam< unsigned long > > SLpatternMask
Super layer pattern mask for which MLP is trained for all networks.
std::vector< std::vector< NNTParam< float > > > nHidden
Number of nodes in each hidden layer for all networks or factor to multiply with number of inputs.
std::vector< std::vector< NNTParam< float > > > thetaRangeTrain
Theta region for which MLP is trained in degree for all networks.
bool checkarr(std::vector< std::vector< NNTParam< X > > > vec)
check, if a vector is already set.
NNTParam< unsigned > tMax
Maximal drift time, identical for all networks.
std::vector< NNTParam< X > > read1dArray(std::string keyx, bool locked)
fill the array from a given string that looks like: [1,2,3]
std::vector< NNTParam< unsigned long > > SLpattern
Super layer pattern for which MLP is trained for all networks.
std::string print2dArray(const std::string &name, std::vector< std::vector< NNTParam< X > > > vecvec)
this is a class for piping the output of a 2d array to a string with brackets
NNTParam< bool > rescaleTarget
flag to allow for target tracks lying out of the output range to be rescaled during training.
std::vector< std::vector< NNTParam< float > > > IDRanges
relative ID range of the relevant wire IDs of the track segments that are taken into consideration wh...
NNTParam< bool > multiplyHidden
If true, multiply nHidden with number of input nodes.
NNTParam< bool > targetTheta
train theta as output
NNTParam< unsigned > nOutput
number of output nodes
std::vector< std::vector< NNTParam< float > > > phiRangeUse
Phi region for which MLP is used in degree for all networks.
NNTParam< unsigned > ETOption
Determine, how the event time should be obtained.
NNTParam< bool > targetZ
train z as output
NNTParam< bool > cutSum
only used in the idhist module.
std::vector< std::vector< NNTParam< X > > > read2dArray(std::string keyx, bool locked)
fill the array from a given string that looks like: [[1,2],[3, 4]]
std::vector< std::vector< NNTParam< float > > > invptRangeTrain
Charge / Pt region for which MLP is trained in 1/GeV for all networks.
std::vector< std::vector< NNTParam< float > > > phiRangeTrain
Phi region for which MLP is trained in degree for all networks.
void loadconfigtxt(const std::string &filename)
load the configuration from a file
void saveconfigtxt(const std::string &filename)
save the configuration to a file
std::string print1dArray(const std::string &name, std::vector< NNTParam< X > > vecvec)
this is a class for piping the output of a 1d array to a string with brackets
NNTParam< double > relevantCut
only used in the idhist module.
NNTParam< unsigned > nInput
Network parameters.
std::vector< NNTParam< unsigned > > precision
precision used for the hardware simulation
std::vector< std::vector< NNTParam< float > > > outputScale
Output scale for all networks.
Abstract base class for different kinds of events.