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 wasn't 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 assigned 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") {
126 } else if (par == "outputScale") {
127 outputScale = read2dArray<float>(key, locked);
128 } else if (par == "SLpattern") {
130 } else if (par == "SLpatternMask") {
132 } else if (par == "precision") {
133 precision = read1dArray<unsigned>(key, locked);
134 } else if (par == "AdditionWireMode") {
135 AdditionWireMode = std::stoul(key);
136 } else if (par == "AdditionInputPerSL") {
137 AdditionInputPerSL = std::stoul(key);
138 }
139 }
140}
141template<typename X>
142bool NeuroTriggerParameters::checkarr(std::vector<std::vector<NNTParam<X>>> vec)
143{
144 // check, if a vector is already set. this is done by just checking the first member of the vector.
145 if (vec.size() < 1) {return false;}
146 else if (vec[0].size() < 1) {return false;}
147 else {return vec[0][0].isSet();}
148}
149
150template<typename X>
152{
153 // check, if a vector is already set. this is done by just checking the first member of the vector.
154 if (vec.size() < 1) {return false;}
155 else {return vec[0].isSet();}
156}
157
158void NeuroTriggerParameters::saveconfigtxt(const std::string& filename)
159{
160 // save all the configuration options in a file, which can later be used to initialize a new parameter set.
161 // only parameters, that already have been set are saved. parameters which are locked, are written with a "==".
162 std::ofstream savestream;
163 savestream.open(filename);
164 savestream << "########################################################" << std::endl;
165 savestream << "### Neurotrigger configuration file created by basf2 ###" << std::endl;
166 savestream << "########################################################" << std::endl << std::endl;
167 savestream << "# '=' means the parameter is set and can be changed," << std::endl;
168 savestream << "# '==' means the parameter is locked and should not be changed." << std::endl << std::endl;
169
170 savestream << "# number of input nodes " << std::endl;
171 if (nInput.isSet()) {
172 savestream << "nInput " << (nInput.isLocked() ? "== " : "= ") << nInput << std::endl;
173 savestream << std::endl;
174 } else {savestream << "nInput = 27" << std::endl;}
175 savestream << "# number of output nodes " << std::endl;
176 if (nOutput.isSet()) {
177 savestream << "nOutput " << (nOutput.isLocked() ? "== " : "= ") << nOutput << std::endl;
178 savestream << std::endl;
179 } else {savestream << "nOutput = 2" << std::endl;}
180 savestream << "# If true, relevantCut is applied to the sum over hit counters, " << std::endl;
181 savestream << "# otherwise directly on the hit counters." << std::endl;
182 if (cutSum.isSet()) {
183 savestream << "cutSum " << (cutSum.isLocked() ? "== " : "= ") << cutSum << std::endl;
184 savestream << std::endl;
185 } else {savestream << "cutSum = 0" << std::endl;}
186 savestream << "# only used in the idhist module. it defines the how much of the idrange is cut off after making the histogram " <<
187 std::endl;
188 if (relevantCut.isSet()) {
189 savestream << "relevantCut " << (relevantCut.isLocked() ? "== " : "= ") << relevantCut << std::endl;
190 savestream << std::endl;
191 } else {savestream << "relevantCut = 0.02" << std::endl;}
192 savestream << "# flag to allow for target tracks lying out of the output range to be rescaled during training. " << std::endl;
193 if (rescaleTarget.isSet()) {
194 savestream << "rescaleTarget " << (rescaleTarget.isLocked() ? "== " : "= ") << rescaleTarget << std::endl;
195 savestream << std::endl;
196 } else {savestream << "rescaleTarget = 0" << std::endl;}
197 savestream << "# Number of networks. For network specific parameters you can give " << std::endl;
198 savestream << "# either a list with values for each network, or a single value that will be used" << std::endl;
199 savestream << "# for all. The ranges are also valid if nPhi * nPt * nTheta * nPattern = nMLPs. " << std::endl;
200 if (nMLP.isSet()) {
201 savestream << "nMLP " << (nMLP.isLocked() ? "== " : "= ") << nMLP << std::endl;
202 savestream << std::endl;
203 } else {savestream << "nMLP = 5" << std::endl;}
204 savestream << "# train z as output " << std::endl;
205 if (targetZ.isSet()) {
206 savestream << "targetZ " << (targetZ.isLocked() ? "== " : "= ") << targetZ << std::endl;
207 savestream << std::endl;
208 } else {savestream << "targetZ = 1" << std::endl;}
209 savestream << "# train theta as output " << std::endl;
210 if (targetTheta.isSet()) {
211 savestream << "targetTheta " << (targetTheta.isLocked() ? "== " : "= ") << targetTheta << std::endl;
212 savestream << std::endl;
213 } else {savestream << "targetTheta = 1" << std::endl;}
214 savestream << "# If true, multiply nHidden with number of input nodes. " << std::endl;
215 if (multiplyHidden.isSet()) {
216 savestream << "multiplyHidden " << (multiplyHidden.isLocked() ? "== " : "= ") << multiplyHidden << std::endl;
217 savestream << std::endl;
218 } else {savestream << "multiplyHidden = 0" << std::endl;}
219 savestream << "# Maximal drift time, identical for all networks. " << std::endl;
220 if (tMax.isSet()) {
221 savestream << "tMax " << (tMax.isLocked() ? "== " : "= ") << tMax << std::endl;
222 savestream << std::endl;
223 } else {savestream << "tMax = 256" << std::endl;}
224 savestream << "# Determine, how the event time should be obtained. The options are:" << std::endl;
225 for (unsigned i = 0; i < 11; i++) {
226 savestream << "# " << i << ": " << to_strTiming(i) << std::endl;
227 }
228 if (ETOption.isSet()) {
229 savestream << "ETOption " << (ETOption.isLocked() ? "== " : "= ") << ETOption << std::endl;
230 savestream << std::endl;
231 } else {savestream << "ETOption = 7" << std::endl;}
232 savestream << "# Phi region for which MLP is used in degree for all networks. " << std::endl;
233 if (checkarr(phiRangeUse)) {
234 savestream << print2dArray<float>("phiRangeUse", phiRangeUse);
235 savestream << std::endl;
236 } else {savestream << "phiRangeUse = [[0, 360]]" << std::endl;}
237 savestream << "# relative ID range of the relevant wire IDs of the track segments " << std::endl;
238 savestream << "# that are taken into consideration when determining the best fitting track segments. " << std::endl;
239 if (checkarr(IDRanges)) {
240 savestream << print2dArray<float>("IDRanges", IDRanges);
241 savestream << std::endl;
242 } else {
243 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],";
244 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],";
245 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],";
246 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],";
247 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]]";
248 savestream << std::endl;
249 }
250 savestream << "# Theta region for which MLP is used in degree for all networks. " << std::endl;
251 if (checkarr(thetaRangeUse)) {
252 savestream << print2dArray<float>("thetaRangeUse", thetaRangeUse);
253 savestream << std::endl;
254 } else {savestream << "thetaRangeUse = [[10, 170]]" << std::endl;}
255 savestream << "# Charge / Pt region for which MLP is used in 1/GeV for all networks. " << std::endl;
256 if (checkarr(invptRangeUse)) {
257 savestream << print2dArray<float>("invptRangeUse", invptRangeUse);
258 savestream << std::endl;
259 } else {savestream << "invptRangeUse = [[-5, 5]]" << std::endl;}
260 savestream << "# Phi region for which MLP is trained in degree for all networks. " << std::endl;
261 savestream << "# Can be larger than use range to avoid edge effects. " << std::endl;
262 if (checkarr(phiRangeTrain)) {
263 savestream << print2dArray<float>("phiRangeTrain", phiRangeTrain);
264 savestream << std::endl;
265 } else {savestream << "phiRangeTrain = [[0, 360]]" << std::endl;}
266 savestream << "# Theta region for which MLP is trained in degree for all networks. " << std::endl;
267 savestream << "# Can be larger than use range to avoid edge effects. " << std::endl;
269 savestream << print2dArray<float>("thetaRangeTrain", thetaRangeTrain);
270 savestream << std::endl;
271 } else {savestream << "thetaRangeTrain = [[10, 170]]" << std::endl;}
272 savestream << "# charge/Pt region for which MLP is trained in degree for all networks. " << std::endl;
273 savestream << "# Can be larger than use range to avoid edge effects. " << std::endl;
275 savestream << print2dArray<float>("invptRangeTrain", invptRangeTrain);
276 savestream << std::endl;
277 } else {savestream << "invptRangeTrain = [[-5, 5]]" << std::endl;}
278 savestream << "# Number of nodes in each hidden layer for all networks" << std::endl;
279 savestream << "# or factor to multiply with number of inputs." << std::endl;
280 savestream << "# The number of layers is derived from the shape." << std::endl;
281 if (checkarr(nHidden)) {
282 savestream << print2dArray<float>("nHidden", nHidden);
283 savestream << std::endl;
284 } else {savestream << "nHidden = [[81]]" << std::endl;}
285 savestream << "# Maximum number of hits in a single super layer for all networks. " << std::endl;
286 if (checkarr(maxHitsPerSL)) {
287 savestream << print1dArray<unsigned short>("maxHitsPerSL", maxHitsPerSL);
288 savestream << std::endl;
289 } else {savestream << "maxHitsPerSL = [1]" << std::endl;}
290 savestream << "# Output scale for all networks. " << std::endl;
291 if (checkarr(outputScale)) {
292 savestream << print2dArray<float>("outputScale", outputScale);
293 savestream << std::endl;
294 } else {savestream << "outputScale = [[-100, 100, 10, 170]]" << std::endl;}
295 savestream << "# Super layer pattern for which MLP is trained for all networks." << std::endl;
296 savestream << "# Binary pattern of 9 * maxHitsPerSL bits (on/off for each hit)." << std::endl;
297 savestream << "# 0 in bit <i>: hits from super layer <i> are not used." << std::endl;
298 savestream << "# 1 in bit <i>: hits from super layer <i> are used." << std::endl;
299 savestream << "# SLpattern = 0: use any hits present, don't check the pattern. " << std::endl;
300 if (checkarr(SLpattern)) {
301 savestream << print1dArray<unsigned long>("SLpattern", SLpattern);
302 savestream << std::endl;
303 } else {savestream << "SLpattern = [511, 383, 479, 503, 509]" << std::endl;}
304 savestream << "# Super layer pattern mask for which MLP is trained for all networks." << std::endl;
305 savestream << "# Binary pattern of 9 * maxHitsPerSL bits (on/off for each hit)." << std::endl;
306 savestream << "# 0 in bit <i>: super layer <i> may or may not have a hit." << std::endl;
307 savestream << "# 1 in bit <i>: super layer <i>" << std::endl;
308 savestream << "# - must have a hit if SLpattern bit <i> = 1" << std::endl;
309 savestream << "# - must not have a hit if SLpattenr bit <i> = 0 " << std::endl;
310 if (checkarr(SLpatternMask)) {
311 savestream << print1dArray<unsigned long>("SLpatternMask", SLpatternMask);
312 savestream << std::endl;
313 } else {savestream << "SLpatternMask = [170]" << std::endl;}
314 savestream << "# precision used for the hardware simulation " << std::endl;
315 if (checkarr(precision)) {
316 savestream << print1dArray<unsigned>("precision", precision);
317 savestream << std::endl;
318 } else {savestream << "precision = [12, 8, 8, 12, 10, 10]" << std::endl;}
319 savestream << "# Set Addition Wire output mode, 0 for default mode, 1 for full hits case and 2 for selected hits case" <<
320 std::endl;
321 if (AdditionWireMode.isSet()) {
322 savestream << "AdditionWireMode " << (AdditionWireMode.isLocked() ? "== " : "= ") << AdditionWireMode << std::endl;
323 savestream << std::endl;
324 } else {savestream << "AdditionWireMode = 0" << std::endl;}
325 savestream <<
326 "# Only used when AdditionWireMode != 0, if mode ==1 , InputPerSL can be 11 (only drift time) and 22 (drift time + ADC ); if mode ==2, InputPerSL can be 3 * n , n equal to the number of wire selected "
327 <<
328 std::endl;
329 if (AdditionInputPerSL.isSet()) {
330 savestream << "AdditionInputPerSL " << (AdditionInputPerSL.isLocked() ? "== " : "= ") << AdditionInputPerSL << std::endl;
331 savestream << std::endl;
332 } else {savestream << "AdditionInputPerSL = 0" << std::endl;}
333
334 savestream.close();
335}
336
337template<typename X>
338std::string NeuroTriggerParameters::print2dArray(const std::string& name, std::vector<std::vector<NNTParam<X>>> vecvec)
339{
340 // this is a class for piping the output of a 2d array to a string with brackets
341 std::stringstream savestream;
342 savestream << name << " " << (vecvec[0][0].isLocked() ? "== " : "= ") << "[";
343 bool outcomma = false;
344 for (auto x : vecvec) {
345 if (outcomma) {savestream << ",";}
346 outcomma = true;
347 savestream << "[";
348 bool incomma = false;
349 for (auto y : x) {
350 if (incomma) {savestream << ",";}
351 incomma = true;
352 savestream << y;
353 }
354 savestream << "]";
355 }
356 savestream << "]" << std::endl;
357 return savestream.str();
358}
359template<typename X>
360std::string NeuroTriggerParameters::print1dArray(const std::string& name, std::vector<NNTParam<X>> vecvec)
361{
362 // this is a class for piping the output of a 1d array to a string with brackets
363 std::stringstream savestream;
364 savestream << name << " " << (vecvec[0].isLocked() ? "== " : "= ") << "[";
365 bool incomma = false;
366 for (auto y : vecvec) {
367 if (incomma) {savestream << ",";}
368 incomma = true;
369 savestream << y;
370 }
371 savestream << "]" << std::endl;
372 return savestream.str();
373}
374template<typename X>
375std::vector<std::vector<NNTParam<X>>> NeuroTriggerParameters::read2dArray(std::string keyx, bool locked)
376{
377 std::vector<std::vector<NNTParam<X>>> retarr;
378 std::string key = keyx;
379 // parse the brackets here to fill the vector: [[1,2], 3,4]]
380 key = key.substr(key.find("[") + 1, std::string::npos); // without outer brackets: [1,2], [3,4]
381 for (std::size_t ipos = 0; ipos != std::string::npos; ipos = key.find("[", ipos + 1)) {
382 std::string pairstr = key.substr(ipos + 1, key.find("]", ipos + 1) - ipos - 1); // this should be 1,2 now
383 std::vector<NNTParam<X>> newpair;
384 std::size_t jpos;
385 for (jpos = 0; jpos != std::string::npos; jpos = pairstr.find(",", jpos)) {
386 if (!(jpos == 0)) {jpos++;}
387 newpair.push_back(NNTParam<X>(std::stof(pairstr.substr(jpos, pairstr.find(",") - jpos))));
388 if (locked) {newpair.back().lock();}
389 }
390 retarr.push_back(newpair);
391 }
392 return retarr;
393}
394
395template<typename X>
396std::vector<NNTParam<X>> NeuroTriggerParameters::read1dArray(std::string keyx, bool locked)
397{
398 std::string key = keyx;
399 // parse the brackets here to fill the vector: [[1,2], 3,4]]
400 std::string pairstr = key.substr(1, key.find("]", 1) - 1); // this should be 1,2 now
401 std::vector<NNTParam<X>> newpair;
402 std::size_t jpos;
403 for (jpos = 0; jpos != std::string::npos; jpos = pairstr.find(",", jpos)) {
404 if (!(jpos == 0)) {jpos++;}
405 newpair.push_back(NNTParam<X>(std::stof(pairstr.substr(jpos, pairstr.find(",") - jpos))));
406 if (locked) {newpair.back().lock();}
407 }
408 return newpair;
409}
Class to represent a complete set to describe a Neurotrigger.
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 > AdditionWireMode
Flag for the addtional wire input usage: 0 for default, 1 selected additional wire,...
NNTParam< unsigned > nMLP
Number of networks.
std::vector< NNTParam< unsigned long > > SLpatternMask
Super layer pattern mask for which MLP is trained for all networks.
NNTParam< unsigned > AdditionInputPerSL
Number for the addtional wire input per SL.
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.