8#include <framework/logging/Logger.h>
9#include <trg/cdc/NeuroTrigger.h>
10#include <trg/cdc/NeuroTriggerParameters.h>
11#include <trg/cdc/dataobjects/CDCTriggerMLPData.h>
12#include <cdc/geometry/CDCGeometryPar.h>
13#include <framework/gearbox/Const.h>
14#include <framework/gearbox/Unit.h>
15#include <framework/datastore/StoreObjPtr.h>
16#include <framework/datastore/StoreArray.h>
17#include <trg/cdc/dbobjects/CDCTriggerNeuroConfig.h>
18#include <trg/cdc/dataobjects/CDCTriggerTrack.h>
22#include "boost/iostreams/filter/gzip.hpp"
23#include "boost/iostreams/filtering_streambuf.hpp"
24#include "boost/iostreams/filtering_stream.hpp"
25#include "boost/multi_array.hpp"
26#define BOOST_MULTI_ARRAY_NO_GENERATORS
40 if (p.nHidden.size() != 1 && p.nHidden.size() != p.nMLP) {
41 B2ERROR(
"Number of nHidden lists should be 1 or " << p.nMLP);
44 if (p.outputScale.size() != 1 && p.outputScale.size() != p.nMLP) {
45 B2ERROR(
"Number of outputScale lists should be 1 or " << p.nMLP);
48 bool rangeProduct = (p.phiRangeUse.size() * p.invptRangeUse.size() * p.thetaRangeUse.size() * p.SLpattern.size() == p.nMLP);
50 if (p.phiRangeUse.size() != 1 && p.phiRangeUse.size() != p.nMLP) {
51 B2ERROR(
"Number of phiRangeUse.lists should be 1 or " << p.nMLP);
54 if (p.invptRangeUse.size() != 1 && p.invptRangeUse.size() != p.nMLP) {
55 B2ERROR(
"Number of invptRangeUse.lists should be 1 or " << p.nMLP);
58 if (p.thetaRangeUse.size() != 1 && p.thetaRangeUse.size() != p.nMLP) {
59 B2ERROR(
"Number of thetaRangeUse.lists should be 1 or " << p.nMLP);
62 if (p.SLpattern.size() != 1 && p.SLpattern.size() != p.nMLP) {
63 B2ERROR(
"Number of SLpattern lists should be 1 or " << p.nMLP);
68 if (p.maxHitsPerSL.size() != 1 && p.maxHitsPerSL.size() != p.SLpattern.size()) {
69 B2ERROR(
"Number of maxHitsPerSL lists should be 1 or " << p.SLpattern.size());
72 if (p.SLpatternMask.size() != 1 && p.SLpatternMask.size() != p.SLpattern.size()) {
73 B2ERROR(
"Number of SLpatternMask lists should be 1 or " << p.SLpattern.size());
77 if (p.targetZ.isSet() || p.targetTheta.isSet()) {
78 unsigned short nTarget = int(p.targetZ) + int(p.targetTheta);
80 B2ERROR(
"No outputs! Turn on either targetZ or targetTheta.");
85 for (
unsigned iPhi = 0; iPhi < p.phiRangeUse.size(); ++iPhi) {
86 if (p.phiRangeUse[iPhi].size() != 2) {
87 B2ERROR(
"phiRangeUse should be exactly 2 values");
91 if (p.phiRangeUse[iPhi][0] >= p.phiRangeUse[iPhi][1]) {
92 B2ERROR(
"phiRangeUse should be smaller than phiRangeUse");
95 if (p.phiRangeUse[iPhi][0] < -360. || p.phiRangeUse[iPhi][1] > 360. ||
96 (p.phiRangeUse[iPhi][1] - p.phiRangeUse[iPhi][0]) > 360.) {
97 B2ERROR(
"phiRangeUse should be in [-360, 360], with maximal width of 360");
101 for (
unsigned iPt = 0; iPt < p.invptRangeUse.size(); ++iPt) {
102 if (p.invptRangeUse[iPt].size() != 2) {
103 B2ERROR(
"invptRangeUse should be exactly 2 values");
106 if (p.invptRangeUse[iPt][0] >= p.invptRangeUse[iPt][1]) {
107 B2ERROR(
"invptRangeUse should be smaller than invptRangeUse");
111 for (
unsigned iTheta = 0; iTheta < p.thetaRangeUse.size(); ++iTheta) {
112 if (p.thetaRangeUse[iTheta].size() != 2) {
113 B2ERROR(
"thetaRangeUse should be exactly 2 values");
117 if (p.thetaRangeUse[iTheta][0] >= p.thetaRangeUse[iTheta][1]) {
118 B2ERROR(
"thetaRangeUse should be smaller than thetaRangeUse");
121 if (p.thetaRangeUse[iTheta][0] < 0. || p.thetaRangeUse[iTheta][1] > 180.) {
122 B2ERROR(
"thetaRangeUse should be in [0, 180]");
126 int nTarget = (int) p.targetZ + (
int) p.targetTheta;
127 if (p.outputScale.size() == p.nMLP || p.outputScale.size() == 1) {
128 for (
unsigned iScale = 0; iScale < p.outputScale.size(); ++iScale) {
129 if (p.outputScale[iScale].size() != 2 *
static_cast<unsigned int>(nTarget)) {
130 B2ERROR(
"outputScale should be exactly " << 2 * nTarget <<
" values");
135 B2ERROR(
"the size of outputscale should be 1 or match the number of experts");
138 if (p.phiRangeUse.size() != p.phiRangeTrain.size()) {
139 B2ERROR(
"Number of phiRangeUse.lists and phiRangeTrain lists should be equal.");
142 for (
unsigned iPhi = 0; iPhi < p.phiRangeUse.size(); ++iPhi) {
143 if (p.phiRangeTrain[iPhi].size() != 2) {
144 B2ERROR(
"phiRangeTrain should be exactly 2 values.");
146 }
else if (p.phiRangeTrain[iPhi][0] > p.phiRangeUse[iPhi][0] ||
147 p.phiRangeTrain[iPhi][1] < p.phiRangeUse[iPhi][1]) {
148 B2ERROR(
"phiRangeTrain should be wider than phiRangeUse.or equal.");
153 if (p.invptRangeUse.size() != p.invptRangeTrain.size()) {
154 B2ERROR(
"Number of invptRangeUse.lists and invptRangeTrain lists should be equal.");
157 for (
unsigned iPt = 0; iPt < p.invptRangeUse.size(); ++iPt) {
158 if (p.invptRangeTrain[iPt].size() != 2) {
159 B2ERROR(
"invptRangeTrain should be exactly 2 values.");
161 }
else if (p.invptRangeTrain[iPt][0] > p.invptRangeUse[iPt][0] ||
162 p.invptRangeTrain[iPt][1] < p.invptRangeUse[iPt][1]) {
163 B2ERROR(
"invptRangeTrain should be wider than invptRangeUse.or equal.");
168 if (p.thetaRangeUse.size() != p.thetaRangeTrain.size()) {
169 B2ERROR(
"Number of thetaRangeUse.lists and thetaRangeTrain lists should be equal.");
172 for (
unsigned iTheta = 0; iTheta < p.thetaRangeUse.size(); ++iTheta) {
173 if (p.thetaRangeTrain[iTheta].size() != 2) {
174 B2ERROR(
"thetaRangeTrain should be exactly 2 values.");
176 }
else if (p.thetaRangeTrain[iTheta][0] > p.thetaRangeUse[iTheta][0] ||
177 p.thetaRangeTrain[iTheta][1] < p.thetaRangeUse[iTheta][1]) {
178 B2ERROR(
"thetaRangeTrain should be wider than thetaRangeUse.or equal.");
188 for (
unsigned iMLP = 0; iMLP < p.nMLP; ++iMLP) {
193 unsigned short maxHits = (p.maxHitsPerSL.size() == 1) ? p.maxHitsPerSL[0] : p.maxHitsPerSL[indices[3]];
194 unsigned long SLpattern = p.SLpattern[indices[3]];
195 unsigned long SLpatternMask = (p.SLpatternMask.size() == 1) ? p.SLpatternMask[0] : p.SLpatternMask[indices[3]];
196 unsigned short nInput = 27 * maxHits;
197 vector<
NNTParam<float>> nHidden = (p.nHidden.size() == 1) ? p.nHidden[0] : p.nHidden[iMLP];
198 vector<unsigned short> nNodes = {nInput};
199 for (
unsigned iHid = 0; iHid < nHidden.size(); ++iHid) {
200 if (p.multiplyHidden) {
201 nNodes.push_back(nHidden[iHid] * nNodes[0]);
203 nNodes.push_back(nHidden[iHid]);
206 nNodes.push_back(nTarget);
207 unsigned short targetVars = int(p.targetZ) + (int(p.targetTheta) << 1);
209 vector<float> phiRangeUse = p.tcastvector<
float>(p.phiRangeUse)[indices[0]];
210 vector<float> invptRangeUse = p.tcastvector<
float>(p.invptRangeUse)[indices[1]];
211 vector<float> thetaRangeUse = p.tcastvector<
float>(p.thetaRangeUse)[indices[2]];
212 vector<float> phiRangeTrain = p.tcastvector<
float>(p.phiRangeTrain)[indices[0]];
213 vector<float> invptRangeTrain = p.tcastvector<
float>(p.invptRangeTrain)[indices[1]];
214 vector<float> thetaRangeTrain = p.tcastvector<
float>(p.thetaRangeTrain)[indices[2]];
215 B2DEBUG(50,
"Ranges for sector " << iMLP
216 <<
": phiRange [" << phiRangeUse[0] <<
", " << phiRangeUse[1]
217 <<
"], invptRange [" << invptRangeUse[0] <<
", " << invptRangeUse[1]
218 <<
"], thetaRange [" << thetaRangeUse[0] <<
", " << thetaRangeUse[1]
219 <<
"], SLpattern " << SLpattern);
221 vector<float> outputScale = (p.outputScale.size() == 1) ? p.tcastvector<
float>(p.outputScale)[0] : p.tcastvector<
float>
222 (p.outputScale)[iMLP];
233 outputScale[2 * int(p.targetZ)] *=
Unit::deg;
234 outputScale[2 * int(p.targetZ) + 1] *=
Unit::deg;
238 phiRangeUse, invptRangeUse, thetaRangeUse,
239 phiRangeTrain, invptRangeTrain, thetaRangeTrain,
240 maxHits, SLpattern, SLpatternMask, p.tMax,
244 if (p.IDRanges.size() == p.nMLP) {
245 for (
auto exp : p.IDRanges) {
247 std::vector<float> irange = {exp.begin() + 1, exp.end()};
248 m_MLPs[
static_cast<int>(exp[0])].setRelID(irange);
250 }
else if (p.IDRanges.size() == 0) {
251 B2WARNING(
"idranges have not been initialized yet, did you forget it?");
253 B2ERROR(
"number of idranges should match the number of experts!");
263 std::vector<unsigned> indices = {0, 0, 0, 0};
264 if (p.phiRangeUse.size() * p.invptRangeUse.size() * p.thetaRangeUse.size() * p.SLpattern.size() == p.nMLP) {
265 indices[0] = isector % p.phiRangeUse.size();
266 indices[1] = (isector / p.phiRangeUse.size()) % p.invptRangeUse.size();
267 indices[2] = (isector / (p.phiRangeUse.size() * p.invptRangeUse.size())) % p.thetaRangeUse.size();
268 indices[3] = isector / (p.phiRangeUse.size() * p.invptRangeUse.size() * p.thetaRangeUse.size());
270 indices[0] = (p.phiRangeUse.size() == 1) ? 0 : isector;
271 indices[1] = (p.invptRangeUse.size() == 1) ? 0 : isector;
272 indices[2] = (p.thetaRangeUse.size() == 1) ? 0 : isector;
273 indices[3] = (p.SLpattern.size() == 1) ? 0 : isector;
285 for (
int iSL = 0; iSL < 9; ++iSL) {
287 nTS += cdc.nWiresInLayer(layerId);
289 for (
int priority = 0; priority < 2; ++ priority) {
290 m_radius[iSL][priority] = cdc.senseWireR(layerId + priority);
292 layerId += (iSL > 0 ? 6 : 7);
300 if (!((et_option ==
"fastestpriority") || (et_option ==
"etfhwin") || (et_option ==
"zero") || (et_option ==
"fastest2d"))) {
315 vector<int> indices = {};
318 B2WARNING(
"Trying to select MLP before initializing MLPs.");
323 for (
unsigned isector = 0; isector <
m_MLPs.size(); ++isector) {
324 if (
m_MLPs[isector].inPhiRangeTrain(phi0) &&
m_MLPs[isector].inInvptRangeTrain(invpt)
325 &&
m_MLPs[isector].inThetaRangeTrain(theta)) {
326 indices.push_back(isector);
330 if (indices.size() == 0) {
331 B2DEBUG(150,
"Track does not match any sector.");
332 B2DEBUG(150,
"invpt=" << invpt <<
", phi=" << phi0 * 180. / M_PI <<
", theta=" << theta * 180. / M_PI);
340 vector<int> indices = {};
343 B2WARNING(
"Trying to select MLP before initializing MLPs.");
348 for (
unsigned isector = 0; isector <
m_MLPs.size(); ++isector) {
349 if (
m_MLPs[isector].inPhiRangeUse(phi0) &&
m_MLPs[isector].inInvptRangeUse(invpt)
350 &&
m_MLPs[isector].inThetaRangeUse(theta)) {
351 indices.push_back(isector);
355 if (indices.size() == 0) {
356 B2DEBUG(150,
"Track does not match any sector.");
357 B2DEBUG(150,
"invpt=" << invpt <<
", phi=" << phi0 * 180. / M_PI <<
", theta=" << theta * 180. / M_PI);
367 if (MLPs.size() == 0) {
372 for (
unsigned i = 0; i < MLPs.size(); ++i) {
373 int isector = MLPs[i];
374 unsigned long sectorPattern =
m_MLPs[isector].getSLpattern();
375 B2DEBUG(250,
"hitPattern " << pattern <<
" sectorPattern " << sectorPattern);
377 if (sectorPattern == 0) {
378 B2DEBUG(250,
"found match for general sector");
382 if (pattern == sectorPattern) {
383 B2DEBUG(250,
"found match for hit pattern " << pattern);
390 if (neurotrackinputmode) {
391 B2DEBUG(150,
"No sector found to match pattern, using sector 0" << pattern <<
".");
394 B2DEBUG(150,
"No sector found to match pattern " << pattern <<
".");
404 double omega = track.getOmega();
405 for (
int iSL = 0; iSL < 9; ++iSL) {
406 for (
int priority = 0; priority < 2; ++priority) {
408 asin(
m_radius[iSL][priority] * omega / 2.) :
410 m_idRef[iSL][priority] = remainder(((track.getPhi0() -
m_alpha[iSL][priority]) *
426 double omega = track.getOmega();
427 long phi = round(track.getPhi0() * (1 << precisionPhiAlpha));
429 for (
int iSL = 0; iSL < 9; ++iSL) {
430 for (
int priority = 0; priority < 2; ++priority) {
433 (
m_radius[iSL][priority] * abs(omega) < 2) ?
434 round(asin(
m_radius[iSL][priority] * omega / 2) * (1 << precisionPhiAlpha)) :
435 round(M_PI_2 * (1 << precisionPhiAlpha));
436 long dphi = phi - (long(
m_alpha[iSL][priority]));
438 long(dphi * round((
m_TSoffset[iSL + 1] -
m_TSoffset[iSL]) / 2. / M_PI * (1 << precisionScale)) /
439 (
long(1) << (precisionPhiAlpha + precisionScale - precisionId)));
441 m_alpha[iSL][priority] /= (1 << precisionPhiAlpha);
442 m_idRef[iSL][priority] /= (1 << precisionId);
450 int iSL = hit.getISuperLayer();
451 int priority = hit.getPriorityPosition();
453 double relId = hit.getSegmentID() + 0.5 * (((priority >> 1) & 1) - (priority & 1))
464 B2DEBUG(200,
"looping over axials:");
465 for (
unsigned ihit = 0; ihit < Hits.
size(); ++ihit) {
467 if (Hits.
weight(ihit) < 0)
continue;
468 unsigned short iSL = Hits[ihit]->getISuperLayer();
469 if (iSL % 2 == 1 && onlyAxials) {
continue;}
471 B2DEBUG(200,
" check drifttime: SL" + std::to_string(iSL) +
",ID = " + std::to_string(Hits[ihit]->getSegmentID()) +
", t = " +
472 std::to_string(Hits[ihit]->priorityTime()));
473 double relId =
getRelId(*Hits[ihit]);
474 if (
m_MLPs[isector].isRelevant(relId, iSL) &&
475 Hits[ihit]->priorityTime() < tlow) {
476 tlow = Hits[ihit]->priorityTime();
477 B2DEBUG(200,
" new tlow: " << std::to_string(tlow));
489 B2DEBUG(20,
"Used event time option is different to the one set in the MLP"
490 <<
LogVar(
"et_option", et_option) <<
LogVar(
"isector", isector)
493 if (et_option ==
"fastestpriority") {
494 B2DEBUG(200,
"et_option is 'fastestpriority'");
507 }
else if (et_option ==
"fastest2d") {
519 }
else if (et_option ==
"zero") {
522 }
else if (et_option ==
"etf_only") {
528 B2ERROR(
"No ETF output, but forced to use ETF!");
532 }
else if (et_option ==
"etf_or_fastestpriority") {
538 getEventTime(isector, track,
"fastestpriority", neuroinputmode);
552 }
else if (et_option ==
"min_etf_fastestpriority") {
559 getEventTime(isector, track,
"fastestpriority", neuroinputmode);
563 }
else if (et_option ==
"etf_or_fastest2d") {
569 getEventTime(isector, track,
"fastest2d", neuroinputmode);
583 }
else if (et_option ==
"etf_or_zero") {
592 }
else if (et_option ==
"etfcc") {
593 if (track.getHasETFTime()) {
594 m_T0 = track.getETF_unpacked();
601 }
else if (et_option ==
"etfcc_or_zero") {
602 if (track.getHasETFTime()) {
603 m_T0 = track.getETF_unpacked();
610 }
else if (et_option ==
"etfcc_or_fastestpriority") {
611 if (track.getHasETFTime()) {
612 m_T0 = track.getETF_unpacked();
615 getEventTime(isector, track,
"fastestpriority", neuroinputmode);
618 }
else if (et_option ==
"etfhwin") {
619 m_T0 = track.getETF_recalced();
623 B2ERROR(
"No valid parameter for et_option (" << et_option <<
" )!");
632 unsigned long driftth = 0;
633 vector<unsigned> nHits;
638 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ ihit) {
640 if (axialHits.
weight(ihit) < 0) {
643 unsigned short iSL = axialHits[ihit]->getISuperLayer();
645 if ((!neurotrackinputmode) && (iSL % 2 == 1))
continue;
647 int t = (
m_hasT0) ? axialHits[ihit]->priorityTime() -
m_T0 : 0;
648 double relId =
getRelId(*axialHits[ihit]);
649 if (t < 0 || t > expert.getTMax()) {
650 if (expert.isRelevant(relId, iSL)) {
651 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
652 driftth |= 1 << (8 - iSL + 9 * nHits[iSL]);
658 if (!neurotrackinputmode) {
663 if (iSL % 2 == 0)
continue;
667 if (t < 0 || t > expert.getTMax()) {
668 if (expert.isRelevant(relId, iSL)) {
669 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
670 driftth |= 1 << (8 - iSL + 9 * nHits[iSL]);
682 unsigned long chitPattern = 0;
683 vector<unsigned> nHits;
688 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ ihit) {
690 if (axialHits.
weight(ihit) < 0) {
693 unsigned short iSL = axialHits[ihit]->getISuperLayer();
695 if ((!neurotrackinputmode) && (iSL % 2 == 1))
continue;
696 double relId =
getRelId(*axialHits[ihit]);
697 if (expert.isRelevant(relId, iSL)) {
698 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
699 chitPattern |= 1 << (iSL + 9 * nHits[iSL]);
704 if (!neurotrackinputmode) {
709 if (iSL % 2 == 0)
continue;
712 if (expert.isRelevant(relId, iSL)) {
713 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
714 chitPattern |= 1 << (iSL + 9 * nHits[iSL]);
727 unsigned long hitPattern = 0;
728 vector<unsigned> nHits;
733 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ ihit) {
735 if (axialHits.
weight(ihit) < 0) {
738 unsigned short iSL = axialHits[ihit]->getISuperLayer();
740 if ((!neurotrackinputmode) && (iSL % 2 == 1))
continue;
741 double relId =
getRelId(*axialHits[ihit]);
743 if (expert.isRelevant(relId, iSL)) {
744 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
745 hitPattern |= 1 << (iSL + 9 * nHits[iSL]);
748 B2DEBUG(250,
"hit in SL " << iSL);
750 B2DEBUG(250,
"hit in SL " << iSL <<
" not relevant (relId = " << relId <<
")");
753 if (!neurotrackinputmode) {
758 if (iSL % 2 == 0)
continue;
760 if (expert.isRelevant(relId, iSL)) {
761 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
762 hitPattern |= 1 << (iSL + 9 * nHits[iSL]);
765 B2DEBUG(250,
"hit in SL " << iSL);
767 B2DEBUG(250,
"hit in SL " << iSL <<
" not relevant (relId = " << relId <<
")");
771 B2DEBUG(250,
"hitPattern " << hitPattern);
772 return hitPattern & expert.getSLpatternMask();
779 vector<unsigned> selectedHitIds = {};
782 tMin.assign(expert.nNodesLayer(0), expert.getTMax());
783 vector<bool> LRknown;
784 LRknown.assign(expert.nNodesLayer(0),
false);
786 hitIds.assign(expert.nNodesLayer(0), -1);
787 vector<unsigned> nHits;
793 B2DEBUG(250,
"start hit loop over all related hits");
798 for (
unsigned ihit = 0; ihit < allHits.
size(); ++ihit) {
800 if (allHits.
weight(ihit) < 0)
continue;
801 unsigned short iSL = allHits[ihit]->getISuperLayer();
802 if (expert.getSLpatternUnmasked() != 0 &&
803 !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
804 B2DEBUG(250,
"skipping hit in SL " << iSL);
808 int t = (
m_hasT0) ? allHits[ihit]->priorityTime() -
m_T0 : 0;
811 }
else if (t > expert.getTMax()) {
812 t = expert.getTMax();
814 double relId =
getRelId(*allHits[ihit]);
815 if (expert.isRelevant(relId, iSL)) {
817 unsigned short iRef = iSL;
818 if (expert.getMaxHitsPerSL() > 1) {
819 if (nHits[iSL] < expert.getMaxHitsPerSL() &&
820 (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
821 iRef += 9 * nHits[iSL];
824 for (
unsigned compare = iSL; compare < iSL + 9 * nHits[iSL]; compare += 9) {
825 if ((LRknown[iRef] && !LRknown[compare]) ||
826 (LRknown[iRef] == LRknown[compare] && tMin[iRef] < tMin[compare]))
834 useHit = (allHits[ihit]->LRknown() && t <= tMin[iRef]);
836 useHit = (allHits[ihit]->LRknown() || t <= tMin[iRef]);
838 B2DEBUG(250,
"relevant wire SL " << iSL <<
" LR " << allHits[ihit]->getLeftRight()
839 <<
" t " << t <<
" iRef " << iRef <<
" useHit " << useHit);
842 LRknown[iRef] = allHits[ihit]->LRknown();
844 hitIds[iRef] = allHits[ihit]->getArrayIndex();
849 for (
unsigned iHit = 0; iHit < hitIds.size(); ++iHit) {
850 if (hitIds[iHit] >= 0) selectedHitIds.push_back(hitIds[iHit]);
852 return selectedHitIds;
856 bool returnAllRelevant)
859 vector<unsigned> selectedHitIds = {};
862 tMin.assign(expert.nNodesLayer(0), expert.getTMax());
863 vector<bool> LRknown;
864 LRknown.assign(expert.nNodesLayer(0),
false);
866 hitIds.assign(expert.nNodesLayer(0), -1);
867 vector<unsigned> nHits;
873 B2DEBUG(250,
"start axial hit loop");
874 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ihit) {
876 if (axialHits.
weight(ihit) < 0)
continue;
877 unsigned short iSL = axialHits[ihit]->getISuperLayer();
879 if (iSL % 2 == 1)
continue;
880 if (expert.getSLpatternUnmasked() != 0 &&
881 !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
882 B2DEBUG(250,
"skipping hit in SL " << iSL);
887 int t = (
m_hasT0) ? axialHits[ihit]->priorityTime() -
m_T0 : 0;
890 }
else if (t > expert.getTMax()) {
891 t = expert.getTMax();
893 double relId =
getRelId(*axialHits[ihit]);
894 if (expert.isRelevant(relId, iSL)) {
896 unsigned short iRef = iSL;
897 if (expert.getMaxHitsPerSL() > 1) {
898 if (nHits[iSL] < expert.getMaxHitsPerSL() &&
899 (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
900 iRef += 9 * nHits[iSL];
903 for (
unsigned compare = iSL; compare < iSL + 9 * nHits[iSL]; compare += 9) {
904 if ((LRknown[iRef] && !LRknown[compare]) ||
905 (LRknown[iRef] == LRknown[compare] && tMin[iRef] < tMin[compare]))
913 useHit = (axialHits[ihit]->LRknown() && t <= tMin[iRef]);
915 useHit = (axialHits[ihit]->LRknown() || t <= tMin[iRef]);
917 B2DEBUG(250,
"relevant wire SL " << iSL <<
" LR " << axialHits[ihit]->getLeftRight()
918 <<
" t " << t <<
" iRef " << iRef <<
" useHit " << useHit);
921 LRknown[iRef] = axialHits[ihit]->LRknown();
923 hitIds[iRef] = axialHits[ihit]->getArrayIndex();
925 if (returnAllRelevant) selectedHitIds.push_back(axialHits[ihit]->getArrayIndex());
930 B2DEBUG(250,
"start stereo hit loop");
934 if (iSL % 2 == 0)
continue;
935 if (expert.getSLpatternUnmasked() != 0 &&
936 !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
937 B2DEBUG(250,
"skipping hit in SL " << iSL);
944 }
else if (t > expert.getTMax()) {
945 t = expert.getTMax();
948 if (expert.isRelevant(relId, iSL)) {
950 unsigned short iRef = iSL;
951 if (expert.getMaxHitsPerSL() > 1) {
952 if (nHits[iSL] < expert.getMaxHitsPerSL() &&
953 (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
954 iRef += 9 * nHits[iSL];
957 for (
unsigned compare = iSL; compare < iSL + 9 * nHits[iSL]; compare += 9) {
958 if ((LRknown[iRef] && !LRknown[compare]) ||
959 (LRknown[iRef] == LRknown[compare] && tMin[iRef] < tMin[compare]))
967 useHit = (
m_segmentHits[ihit]->LRknown() && t <= tMin[iRef]);
969 useHit = (
m_segmentHits[ihit]->LRknown() || t <= tMin[iRef]);
971 B2DEBUG(250,
"relevant wire SL " << iSL <<
" LR " <<
m_segmentHits[ihit]->getLeftRight()
972 <<
" t " << t <<
" iRef " << iRef <<
" useHit " << useHit);
979 if (returnAllRelevant) selectedHitIds.push_back(ihit);
984 if (!returnAllRelevant) {
985 for (
unsigned iHit = 0; iHit < hitIds.size(); ++iHit) {
986 if (hitIds[iHit] >= 0) selectedHitIds.push_back(hitIds[iHit]);
989 return selectedHitIds;
997 vector<float> inputVector;
998 inputVector.assign(expert.nNodesLayer(0), 0.);
1000 vector<unsigned> nHits;
1002 for (
unsigned ii = 0; ii < hitIds.size(); ++ii) {
1003 int ihit = hitIds[ii];
1005 unsigned short iRef = iSL + 9 * nHits[iSL];
1011 }
else if (t > expert.getTMax()) {
1012 t = expert.getTMax();
1018 inputVector[3 * iRef] = expert.scaleId(relId, iSL);
1019 float scaleT = pow(2, floor(log2(1. / expert.getTMax())));
1020 inputVector[3 * iRef + 1] = (((LR >> 1) & 1) - (LR & 1)) * t * scaleT;
1021 inputVector[3 * iRef + 2] =
m_alpha[iSL][int(priority < 3)] * 0.5;
1030 vector<float> weights = expert.getWeights();
1031 vector<float> layerinput = input;
1032 vector<float> layeroutput = {};
1034 for (
unsigned il = 1; il < expert.nLayers(); ++il) {
1036 layerinput.push_back(1.);
1038 layeroutput.clear();
1039 layeroutput.assign(expert.nNodesLayer(il), 0.);
1041 for (
unsigned io = 0; io < layeroutput.size(); ++io) {
1043 for (
unsigned ii = 0; ii < layerinput.size(); ++ii) {
1044 layeroutput[io] += layerinput[ii] * weights[iw++];
1047 layeroutput[io] = tanh(layeroutput[io] / 2.);
1050 layerinput = layeroutput;
1052 return expert.unscaleTarget(layeroutput);
1062 unsigned dp = precisionInput + precisionWeights - precisionLUT;
1066 vector<long> inputFix(input.size(), 0);
1067 for (
unsigned ii = 0; ii < input.size(); ++ii) {
1068 inputFix[ii] = long(input[ii] * (1 << precisionInput));
1071 vector<float> weights = expert.getWeights();
1072 vector<long> weightsFix(weights.size(), 0);
1073 for (
unsigned iw = 0; iw < weights.size(); ++iw) {
1074 weightsFix[iw] = long(round(weights[iw] * (1 << precisionWeights)));
1077 unsigned xMax = unsigned(ceil(atanh(1. - 1. / (1 << (precisionTanh + 1))) *
1078 (1 << (precisionLUT + 1))));
1081 vector<long> layerinput = inputFix;
1082 vector<long> layeroutput = {};
1084 for (
unsigned il = 1; il < expert.nLayers(); ++il) {
1086 layerinput.push_back(1 << precisionInput);
1088 layeroutput.clear();
1089 layeroutput.assign(expert.nNodesLayer(il), 0);
1091 for (
unsigned io = 0; io < layeroutput.size(); ++io) {
1093 for (
unsigned ii = 0; ii < layerinput.size(); ++ii) {
1094 layeroutput[io] += layerinput[ii] * weightsFix[iw++];
1097 unsigned long bin = abs(layeroutput[io]) >> dp;
1099 float x = (bin + 0.5 - 1. / (1 << (dp + 1))) / (1 << precisionLUT);
1100 long tanhLUT = (bin < xMax) ?
long(round(tanh(x / 2.) * (1 << precisionTanh))) : (1 << precisionTanh);
1101 layeroutput[io] = (layeroutput[io] < 0) ? -tanhLUT : tanhLUT;
1104 layerinput = layeroutput;
1108 vector<float> output(layeroutput.size(), 0.);
1109 for (
unsigned io = 0; io < output.size(); ++io) {
1110 output[io] = layeroutput[io] / float(1 << precisionTanh);
1112 return expert.unscaleTarget(output);
1118 B2INFO(
"Saving networks to file " << filename <<
", array " << arrayname);
1119 TFile datafile(filename.c_str(),
"UPDATE");
1120 TObjArray* MLPs =
new TObjArray(
m_MLPs.size());
1121 for (
unsigned isector = 0; isector <
m_MLPs.size(); ++isector) {
1122 MLPs->Add(&
m_MLPs[isector]);
1124 MLPs->Write(arrayname.c_str(), TObject::kSingleKey | TObject::kOverwrite);
1131 std::ifstream gzipfile(filename, ios_base::in | ios_base::binary);
1132 boost::iostreams::filtering_istream arrayStream;
1133 arrayStream.push(boost::iostreams::gzip_decompressor());
1134 arrayStream.push(gzipfile);
1136 if (gzipfile.is_open()) {
1137 while (arrayStream >> hline) {
1138 for (
unsigned i = 0; i < 18; ++i) {
1139 m_MLPs[hline.exPert].relevantID[i] = hline.relID[i];
1142 }
else {
return false;}
1150 if (filename.size() < 1) {
1153 if (
m_MLPs.size() == 0) {
1154 B2ERROR(
"Could not load Neurotrigger weights from database!");
1158 B2DEBUG(100,
"loaded " <<
m_MLPs.size() <<
" networks from database");
1163 TFile datafile(filename.c_str(),
"READ");
1164 if (!datafile.IsOpen()) {
1165 B2WARNING(
"Could not open file " << filename);
1169 TObjArray* MLPs = (TObjArray*)datafile.Get(arrayname.c_str());
1172 B2WARNING(
"File " << filename <<
" does not contain key " << arrayname);
1176 for (
int isector = 0; isector < MLPs->GetEntriesFast(); ++isector) {
1178 if (expert)
m_MLPs.push_back(*expert);
1179 else B2WARNING(
"Wrong type " << MLPs->At(isector)->ClassName() <<
", ignoring this entry.");
1184 B2DEBUG(100,
"loaded " <<
m_MLPs.size() <<
" networks");
1186 B2INFO(
"Loaded Neurotrigger MLP weights from file: " + filename);
bool hasBinnedEventT0(const Const::EDetector detector) const
Check if one of the detectors in the given set has a binned t0 estimation.
int getBinnedEventT0(const Const::EDetector detector) const
Return the stored binned event t0 for the given detector or 0 if nothing stored.
Class to keep all parameters of an expert MLP for the neuro trigger.
Combination of several CDCHits to a track segment hit for the trigger.
Track created by the CDC trigger.
The Class for CDC Geometry Parameters.
static CDCGeometryPar & Instance(const CDCGeometry *=nullptr)
Static method to get a reference to the CDCGeometryPar instance.
Class to represent a complete set to describe a Neurotrigger.
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...
double m_alpha[9][2]
2D crossing angle of current track
std::vector< CDCTriggerMLP > m_MLPs
List of networks.
double getRelId(const CDCTriggerSegmentHit &hit)
Calculate phi position of a hit relative to 2D track (scaled to number of wires).
DBObjPtr< CDCTriggerNeuroConfig > m_cdctriggerneuroconfig
get NNT payload from database.
void initialize(const Parameters &p)
Set parameters and get some network independent parameters.
std::vector< unsigned > getRangeIndices(const NeuroTriggerParameters &p, unsigned isector)
Get indices for sector ranges in parameter lists.
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.
StoreArray< CDCTriggerSegmentHit > m_segmentHits
StoreArray containing the input track segment hits.
int selectMLPbyPattern(std::vector< int > &MLPs, unsigned long pattern, const bool neurotrackinputmode)
Select one MLP from a list of sector indices.
std::vector< unsigned > m_precision
Fixed point precision in bit after radix point.
std::string get_et_option()
Return value of m_et_option.
unsigned long getInputPattern(unsigned isector, const CDCTriggerTrack &track, const bool neurotrackinputmode)
Calculate input pattern for MLP.
int m_T0
Event time of current event / track.
void save(const std::string &filename, const std::string &arrayname="MLPs")
Save MLPs to file.
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.
bool loadIDHist(const std::string &filename)
function to load idhist from file
std::vector< int > selectMLPsTrain(float phi0, float invpt, float theta)
Select all matching expert MLPs based on the given track parameters.
void setConstants()
Loads parameters from the geometry and precalculates some constants that will be needed.
unsigned m_TSoffset[10]
Number of track segments up to super layer.
double m_radius[9][2]
Radius of the CDC layers with priority wires (2 per super layer)
StoreObjPtr< BinnedEventT0 > m_eventTime
StoreObjPtr containing the event time.
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.
int getLowestTime(unsigned isector, RelationVector< CDCTriggerSegmentHit > Hits, bool onlyAxials)
helper function to get the fastest priority time of given ts array
double m_idRef[9][2]
2D phi position of current track scaled to number of wires
std::string m_hitCollectionName
Name of the StoreArray containing the input track segment hits.
std::vector< float > runMLP(unsigned isector, const std::vector< float > &input)
Run an expert MLP.
bool m_hasT0
Flag to show if stored event time is valid.
Class for type safe access to objects that are referred to in relations.
size_t size() const
Get number of relations.
float weight(int index) const
Get weight with index.
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
int getEntries() const
Get the number of objects in the array.
bool isValid() const
Check whether the object was created.
static const double deg
degree to radians
Class to store variables with their name which were sent to the logging service.
Abstract base class for different kinds of events.