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.");
190 for (
unsigned iMLP = 0; iMLP < p.nMLP; ++iMLP) {
195 unsigned short maxHits = (p.maxHitsPerSL.size() == 1) ? p.maxHitsPerSL[0] : p.maxHitsPerSL[indices[3]];
196 unsigned long SLpattern = p.SLpattern[indices[3]];
197 unsigned long SLpatternMask = (p.SLpatternMask.size() == 1) ? p.SLpatternMask[0] : p.SLpatternMask[indices[3]];
198 unsigned short nInput = 27 * maxHits;
199 if (p.AdditionWireMode != 0)
200 nInput = 9 * (3 + p.AdditionInputPerSL) * maxHits;
201 vector<NNTParam<float>> nHidden = (p.nHidden.size() == 1) ? p.nHidden[0] : p.nHidden[iMLP];
202 vector<unsigned short> nNodes = {nInput};
203 for (
unsigned iHid = 0; iHid < nHidden.size(); ++iHid) {
204 if (p.multiplyHidden) {
205 nNodes.push_back(nHidden[iHid] * nNodes[0]);
207 nNodes.push_back(nHidden[iHid]);
210 nNodes.push_back(nTarget);
211 unsigned short targetVars = int(p.targetZ) + (int(p.targetTheta) << 1);
213 vector<float> phiRangeUse = p.tcastvector<
float>(p.phiRangeUse)[indices[0]];
214 vector<float> invptRangeUse = p.tcastvector<
float>(p.invptRangeUse)[indices[1]];
215 vector<float> thetaRangeUse = p.tcastvector<
float>(p.thetaRangeUse)[indices[2]];
216 vector<float> phiRangeTrain = p.tcastvector<
float>(p.phiRangeTrain)[indices[0]];
217 vector<float> invptRangeTrain = p.tcastvector<
float>(p.invptRangeTrain)[indices[1]];
218 vector<float> thetaRangeTrain = p.tcastvector<
float>(p.thetaRangeTrain)[indices[2]];
219 B2DEBUG(50,
"Ranges for sector " << iMLP
220 <<
": phiRange [" << phiRangeUse[0] <<
", " << phiRangeUse[1]
221 <<
"], invptRange [" << invptRangeUse[0] <<
", " << invptRangeUse[1]
222 <<
"], thetaRange [" << thetaRangeUse[0] <<
", " << thetaRangeUse[1]
223 <<
"], SLpattern " << SLpattern);
225 vector<float> outputScale = (p.outputScale.size() == 1) ? p.tcastvector<
float>(p.outputScale)[0] : p.tcastvector<float>
226 (p.outputScale)[iMLP];
237 outputScale[2 * int(p.targetZ)] *= Unit::deg;
238 outputScale[2 * int(p.targetZ) + 1] *= Unit::deg;
241 m_MLPs.push_back(CDCTriggerMLP(nNodes, targetVars, outputScale,
242 phiRangeUse, invptRangeUse, thetaRangeUse,
243 phiRangeTrain, invptRangeTrain, thetaRangeTrain,
244 maxHits, SLpattern, SLpatternMask, p.tMax,
248 if (p.IDRanges.size() == p.nMLP) {
249 for (
auto exp : p.IDRanges) {
251 std::vector<float> irange = {exp.begin() + 1, exp.end()};
252 m_MLPs[
static_cast<int>(exp[0])].setRelID(irange);
254 }
else if (p.IDRanges.size() == 0) {
255 B2WARNING(
"idranges have not been initialized yet, did you forget it?");
257 B2ERROR(
"number of idranges should match the number of experts!");
267 std::vector<unsigned> indices = {0, 0, 0, 0};
268 if (p.phiRangeUse.size() * p.invptRangeUse.size() * p.thetaRangeUse.size() * p.SLpattern.size() == p.nMLP) {
269 indices[0] = isector % p.phiRangeUse.size();
270 indices[1] = (isector / p.phiRangeUse.size()) % p.invptRangeUse.size();
271 indices[2] = (isector / (p.phiRangeUse.size() * p.invptRangeUse.size())) % p.thetaRangeUse.size();
272 indices[3] = isector / (p.phiRangeUse.size() * p.invptRangeUse.size() * p.thetaRangeUse.size());
274 indices[0] = (p.phiRangeUse.size() == 1) ? 0 : isector;
275 indices[1] = (p.invptRangeUse.size() == 1) ? 0 : isector;
276 indices[2] = (p.thetaRangeUse.size() == 1) ? 0 : isector;
277 indices[3] = (p.SLpattern.size() == 1) ? 0 : isector;
289 for (
int iSL = 0; iSL < 9; ++iSL) {
291 nTS += cdc.nWiresInLayer(layerId);
293 for (
int priority = 0; priority < 5; ++ priority) {
294 m_radius[iSL][priority] = (iSL == 0 ? cdc.senseWireR(layerId + priority) : ((priority & 1) == 1 ? cdc.senseWireR(layerId + ceil(
295 priority / 2.0)) : cdc.senseWireR(layerId - ceil(priority / 2.0))));
297 layerId += (iSL > 0 ? 6 : 7);
305 if (!((et_option ==
"fastestpriority") || (et_option ==
"etfhwin") || (et_option ==
"zero") || (et_option ==
"fastest2d"))) {
320 vector<int> indices = {};
323 B2WARNING(
"Trying to select MLP before initializing MLPs.");
328 for (
unsigned isector = 0; isector <
m_MLPs.size(); ++isector) {
329 if (
m_MLPs[isector].inPhiRangeTrain(phi0) &&
m_MLPs[isector].inInvptRangeTrain(invpt)
330 &&
m_MLPs[isector].inThetaRangeTrain(theta)) {
331 indices.push_back(isector);
335 if (indices.size() == 0) {
336 B2DEBUG(150,
"Track does not match any sector.");
337 B2DEBUG(150,
"invpt=" << invpt <<
", phi=" << phi0 * 180. / M_PI <<
", theta=" << theta * 180. / M_PI);
345 vector<int> indices = {};
348 B2WARNING(
"Trying to select MLP before initializing MLPs.");
353 for (
unsigned isector = 0; isector <
m_MLPs.size(); ++isector) {
354 if (
m_MLPs[isector].inPhiRangeUse(phi0) &&
m_MLPs[isector].inInvptRangeUse(invpt)
355 &&
m_MLPs[isector].inThetaRangeUse(theta)) {
356 indices.push_back(isector);
360 if (indices.size() == 0) {
361 B2DEBUG(150,
"Track does not match any sector.");
362 B2DEBUG(150,
"invpt=" << invpt <<
", phi=" << phi0 * 180. / M_PI <<
", theta=" << theta * 180. / M_PI);
372 if (MLPs.size() == 0) {
377 for (
unsigned i = 0; i < MLPs.size(); ++i) {
378 int isector = MLPs[i];
379 unsigned long sectorPattern =
m_MLPs[isector].getSLpattern();
380 B2DEBUG(250,
"hitPattern " << pattern <<
" sectorPattern " << sectorPattern);
382 if (sectorPattern == 0) {
383 B2DEBUG(250,
"found match for general sector");
387 if (pattern == sectorPattern) {
388 B2DEBUG(250,
"found match for hit pattern " << pattern);
395 if (neurotrackinputmode) {
396 B2DEBUG(150,
"No sector found to match pattern, using sector 0" << pattern <<
".");
399 B2DEBUG(150,
"No sector found to match pattern " << pattern <<
".");
409 double omega = track.getOmega();
410 for (
int iSL = 0; iSL < 9; ++iSL) {
411 for (
int priority = 0; priority < 5; ++priority) {
413 asin(
m_radius[iSL][priority] * omega / 2.) :
415 m_idRef[iSL][priority] = remainder(((track.getPhi0() -
m_alpha[iSL][priority]) *
431 double omega = track.getOmega();
432 long phi = round(track.getPhi0() * (1 << precisionPhiAlpha));
434 for (
int iSL = 0; iSL < 9; ++iSL) {
435 for (
int priority = 0; priority < 2; ++priority) {
438 (
m_radius[iSL][priority] * abs(omega) < 2) ?
439 round(asin(
m_radius[iSL][priority] * omega / 2) * (1 << precisionPhiAlpha)) :
440 round(M_PI_2 * (1 << precisionPhiAlpha));
441 long dphi = phi - (long(
m_alpha[iSL][priority]));
443 long(dphi * round((
m_TSoffset[iSL + 1] -
m_TSoffset[iSL]) / 2. / M_PI * (1 << precisionScale)) /
444 (
long(1) << (precisionPhiAlpha + precisionScale - precisionId)));
446 m_alpha[iSL][priority] /= (1 << precisionPhiAlpha);
447 m_idRef[iSL][priority] /= (1 << precisionId);
455 int iSL = hit.getISuperLayer();
456 int priority = hit.getPriorityPosition();
458 double relId = hit.getSegmentID() + 0.5 * (((priority >> 1) & 1) - (priority & 1))
469 B2DEBUG(200,
"looping over axials:");
470 for (
unsigned ihit = 0; ihit < Hits.
size(); ++ihit) {
472 if (Hits.
weight(ihit) < 0)
continue;
473 unsigned short iSL = Hits[ihit]->getISuperLayer();
474 if (iSL % 2 == 1 && onlyAxials) {
continue;}
476 B2DEBUG(200,
" check drifttime: SL" + std::to_string(iSL) +
",ID = " + std::to_string(Hits[ihit]->getSegmentID()) +
", t = " +
477 std::to_string(Hits[ihit]->priorityTime()));
478 double relId =
getRelId(*Hits[ihit]);
479 if (
m_MLPs[isector].isRelevant(relId, iSL) &&
480 Hits[ihit]->priorityTime() < tlow) {
481 tlow = Hits[ihit]->priorityTime();
482 B2DEBUG(200,
" new tlow: " << std::to_string(tlow));
494 B2DEBUG(20,
"Used event time option is different to the one set in the MLP"
495 <<
LogVar(
"et_option", et_option) <<
LogVar(
"isector", isector)
498 if (et_option ==
"fastestpriority") {
499 B2DEBUG(200,
"et_option is 'fastestpriority'");
512 }
else if (et_option ==
"fastest2d") {
524 }
else if (et_option ==
"zero") {
527 }
else if (et_option ==
"etf_only") {
533 B2ERROR(
"No ETF output, but forced to use ETF!");
537 }
else if (et_option ==
"etf_or_fastestpriority") {
543 getEventTime(isector, track,
"fastestpriority", neuroinputmode);
557 }
else if (et_option ==
"min_etf_fastestpriority") {
561 T0_etf =
m_eventTime->getBinnedEventT0(Const::CDC) / 2;
564 getEventTime(isector, track,
"fastestpriority", neuroinputmode);
568 }
else if (et_option ==
"etf_or_fastest2d") {
574 getEventTime(isector, track,
"fastest2d", neuroinputmode);
588 }
else if (et_option ==
"etf_or_zero") {
597 }
else if (et_option ==
"etfcc") {
598 if (track.getHasETFTime()) {
599 m_T0 = track.getETF_unpacked();
606 }
else if (et_option ==
"etfcc_or_zero") {
607 if (track.getHasETFTime()) {
608 m_T0 = track.getETF_unpacked();
615 }
else if (et_option ==
"etfcc_or_fastestpriority") {
616 if (track.getHasETFTime()) {
617 m_T0 = track.getETF_unpacked();
620 getEventTime(isector, track,
"fastestpriority", neuroinputmode);
623 }
else if (et_option ==
"etfhwin") {
624 m_T0 = track.getETF_recalced();
628 B2ERROR(
"No valid parameter for et_option (" << et_option <<
" )!");
637 unsigned long driftth = 0;
638 vector<unsigned> nHits;
643 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ ihit) {
645 if (axialHits.
weight(ihit) < 0) {
648 unsigned short iSL = axialHits[ihit]->getISuperLayer();
650 if ((!neurotrackinputmode) && (iSL % 2 == 1))
continue;
652 int t = (
m_hasT0) ? axialHits[ihit]->priorityTime() -
m_T0 : 0;
653 double relId =
getRelId(*axialHits[ihit]);
654 if (t < 0 || t > expert.getTMax()) {
655 if (expert.isRelevant(relId, iSL)) {
656 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
657 driftth |= 1 << (8 - iSL + 9 * nHits[iSL]);
663 if (!neurotrackinputmode) {
665 for (
int ihit = 0; ihit <
m_segmentHits.getEntries(); ++ ihit) {
668 if (iSL % 2 == 0)
continue;
672 if (t < 0 || t > expert.getTMax()) {
673 if (expert.isRelevant(relId, iSL)) {
674 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
675 driftth |= 1 << (8 - iSL + 9 * nHits[iSL]);
687 unsigned long chitPattern = 0;
688 vector<unsigned> nHits;
693 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ ihit) {
695 if (axialHits.
weight(ihit) < 0) {
698 unsigned short iSL = axialHits[ihit]->getISuperLayer();
700 if ((!neurotrackinputmode) && (iSL % 2 == 1))
continue;
701 double relId =
getRelId(*axialHits[ihit]);
702 if (expert.isRelevant(relId, iSL)) {
703 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
704 chitPattern |= 1 << (iSL + 9 * nHits[iSL]);
709 if (!neurotrackinputmode) {
711 for (
int ihit = 0; ihit <
m_segmentHits.getEntries(); ++ ihit) {
714 if (iSL % 2 == 0)
continue;
717 if (expert.isRelevant(relId, iSL)) {
718 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
719 chitPattern |= 1 << (iSL + 9 * nHits[iSL]);
732 unsigned long hitPattern = 0;
733 vector<unsigned> nHits;
738 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ ihit) {
740 if (axialHits.
weight(ihit) < 0) {
743 unsigned short iSL = axialHits[ihit]->getISuperLayer();
745 if ((!neurotrackinputmode) && (iSL % 2 == 1))
continue;
746 double relId =
getRelId(*axialHits[ihit]);
748 if (expert.isRelevant(relId, iSL)) {
749 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
750 hitPattern |= 1 << (iSL + 9 * nHits[iSL]);
753 B2DEBUG(250,
"hit in SL " << iSL);
755 B2DEBUG(250,
"hit in SL " << iSL <<
" not relevant (relId = " << relId <<
")");
758 if (!neurotrackinputmode) {
760 for (
int ihit = 0; ihit <
m_segmentHits.getEntries(); ++ ihit) {
763 if (iSL % 2 == 0)
continue;
765 if (expert.isRelevant(relId, iSL)) {
766 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
767 hitPattern |= 1 << (iSL + 9 * nHits[iSL]);
770 B2DEBUG(250,
"hit in SL " << iSL);
772 B2DEBUG(250,
"hit in SL " << iSL <<
" not relevant (relId = " << relId <<
")");
776 B2DEBUG(250,
"hitPattern " << hitPattern);
777 return hitPattern & expert.getSLpatternMask();
784 vector<unsigned> selectedHitIds = {};
787 tMin.assign(expert.nNodesLayer(0), expert.getTMax());
788 vector<bool> LRknown;
789 LRknown.assign(expert.nNodesLayer(0),
false);
791 hitIds.assign(expert.nNodesLayer(0), -1);
792 vector<unsigned> nHits;
798 B2DEBUG(250,
"start hit loop over all related hits");
803 for (
unsigned ihit = 0; ihit < allHits.
size(); ++ihit) {
805 if (allHits.
weight(ihit) < 0)
continue;
806 unsigned short iSL = allHits[ihit]->getISuperLayer();
807 if (expert.getSLpatternUnmasked() != 0 &&
808 !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
809 B2DEBUG(250,
"skipping hit in SL " << iSL);
813 int t = (
m_hasT0) ? allHits[ihit]->priorityTime() -
m_T0 : 0;
816 }
else if (t > expert.getTMax()) {
817 t = expert.getTMax();
819 double relId =
getRelId(*allHits[ihit]);
820 if (expert.isRelevant(relId, iSL)) {
822 unsigned short iRef = iSL;
823 if (expert.getMaxHitsPerSL() > 1) {
824 if (nHits[iSL] < expert.getMaxHitsPerSL() &&
825 (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
826 iRef += 9 * nHits[iSL];
829 for (
unsigned compare = iSL; compare < iSL + 9 * nHits[iSL]; compare += 9) {
830 if ((LRknown[iRef] && !LRknown[compare]) ||
831 (LRknown[iRef] == LRknown[compare] && tMin[iRef] < tMin[compare]))
839 useHit = (allHits[ihit]->LRknown() && t <= tMin[iRef]);
841 useHit = (allHits[ihit]->LRknown() || t <= tMin[iRef]);
843 B2DEBUG(250,
"relevant wire SL " << iSL <<
" LR " << allHits[ihit]->getLeftRight()
844 <<
" t " << t <<
" iRef " << iRef <<
" useHit " << useHit);
847 LRknown[iRef] = allHits[ihit]->LRknown();
849 hitIds[iRef] = allHits[ihit]->getArrayIndex();
854 for (
unsigned iHit = 0; iHit < hitIds.size(); ++iHit) {
855 if (hitIds[iHit] >= 0) selectedHitIds.push_back(hitIds[iHit]);
857 return selectedHitIds;
861 bool returnAllRelevant)
864 vector<unsigned> selectedHitIds = {};
867 tMin.assign(expert.nNodesLayer(0), expert.getTMax());
868 vector<bool> LRknown;
869 LRknown.assign(expert.nNodesLayer(0),
false);
871 hitIds.assign(expert.nNodesLayer(0), -1);
872 vector<unsigned> nHits;
878 B2DEBUG(250,
"start axial hit loop");
879 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ihit) {
881 if (axialHits.
weight(ihit) < 0)
continue;
882 unsigned short iSL = axialHits[ihit]->getISuperLayer();
884 if (iSL % 2 == 1)
continue;
885 if (expert.getSLpatternUnmasked() != 0 &&
886 !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
887 B2DEBUG(250,
"skipping hit in SL " << iSL);
892 int t = (
m_hasT0) ? axialHits[ihit]->priorityTime() -
m_T0 : 0;
895 }
else if (t > expert.getTMax()) {
896 t = expert.getTMax();
898 double relId =
getRelId(*axialHits[ihit]);
899 if (expert.isRelevant(relId, iSL)) {
901 unsigned short iRef = iSL;
902 if (expert.getMaxHitsPerSL() > 1) {
903 if (nHits[iSL] < expert.getMaxHitsPerSL() &&
904 (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
905 iRef += 9 * nHits[iSL];
908 for (
unsigned compare = iSL; compare < iSL + 9 * nHits[iSL]; compare += 9) {
909 if ((LRknown[iRef] && !LRknown[compare]) ||
910 (LRknown[iRef] == LRknown[compare] && tMin[iRef] < tMin[compare]))
918 useHit = (axialHits[ihit]->LRknown() && t <= tMin[iRef]);
920 useHit = (axialHits[ihit]->LRknown() || t <= tMin[iRef]);
922 B2DEBUG(250,
"relevant wire SL " << iSL <<
" LR " << axialHits[ihit]->getLeftRight()
923 <<
" t " << t <<
" iRef " << iRef <<
" useHit " << useHit);
926 LRknown[iRef] = axialHits[ihit]->LRknown();
928 hitIds[iRef] = axialHits[ihit]->getArrayIndex();
930 if (returnAllRelevant) selectedHitIds.push_back(axialHits[ihit]->getArrayIndex());
935 B2DEBUG(250,
"start stereo hit loop");
936 for (
int ihit = 0; ihit <
m_segmentHits.getEntries(); ++ ihit) {
939 if (iSL % 2 == 0)
continue;
940 if (expert.getSLpatternUnmasked() != 0 &&
941 !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
942 B2DEBUG(250,
"skipping hit in SL " << iSL);
949 }
else if (t > expert.getTMax()) {
950 t = expert.getTMax();
953 if (expert.isRelevant(relId, iSL)) {
955 unsigned short iRef = iSL;
956 if (expert.getMaxHitsPerSL() > 1) {
957 if (nHits[iSL] < expert.getMaxHitsPerSL() &&
958 (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
959 iRef += 9 * nHits[iSL];
962 for (
unsigned compare = iSL; compare < iSL + 9 * nHits[iSL]; compare += 9) {
963 if ((LRknown[iRef] && !LRknown[compare]) ||
964 (LRknown[iRef] == LRknown[compare] && tMin[iRef] < tMin[compare]))
972 useHit = (
m_segmentHits[ihit]->LRknown() && t <= tMin[iRef]);
974 useHit = (
m_segmentHits[ihit]->LRknown() || t <= tMin[iRef]);
976 B2DEBUG(250,
"relevant wire SL " << iSL <<
" LR " <<
m_segmentHits[ihit]->getLeftRight()
977 <<
" t " << t <<
" iRef " << iRef <<
" useHit " << useHit);
984 if (returnAllRelevant) selectedHitIds.push_back(ihit);
989 if (!returnAllRelevant) {
990 for (
unsigned iHit = 0; iHit < hitIds.size(); ++iHit) {
991 if (hitIds[iHit] >= 0) selectedHitIds.push_back(hitIds[iHit]);
994 return selectedHitIds;
1003 vector<float> inputVector;
1004 inputVector.assign(expert.nNodesLayer(0), 0.);
1006 vector<unsigned> nHits;
1009 for (
unsigned ii = 0; ii < hitIds.size(); ++ii) {
1010 int ihit = hitIds[ii];
1012 unsigned short iRef = iSL + 9 * nHits[iSL];
1019 }
else if (t > expert.getTMax()) {
1020 t = expert.getTMax();
1025 vector<float> hitpatterntime =
m_segmentHits[ihit]->gethittime();
1027 HitIDs.assign(hitpatterntime.size(), -1);
1028 vector<float> HitTimes;
1029 HitTimes.assign(hitpatterntime.size(), -1);
1036 float scaleT = pow(2, floor(log2(1. / expert.getTMax())));
1037 inputVector[(3 +
m_AdditionInputPerSL) * iRef + 1] = (((LR >> 1) & 1) - (LR & 1)) * t * scaleT;
1043 B2ERROR(
"For extra wire case, please set m_AdditionInputPerSL to 3 * n, where n is the number of extra wire want to include ");
1057 LRV.assign((
int)hitpatterntime.size(), 2);
1059 for (
int j = 0; j < (int) hitpatterntime.size(); j++) {
1060 HitTimes[j] = (((hitpattern >> j) % 2 == 1) ? ((
m_hasT0) ? hitpatterntime[j] -
m_T0 : 0) : 0);
1062 if (HitTimes[j] > expert.getTMax()) HitTimes[j] = expert.getTMax();
1063 if (HitTimes[j] <
m_TMin)LRV[j] = 3;
1064 if (HitTimes[j] < 0)HitTimes[j] = 0;
1066 B2DEBUG(150,
"wire Find hit: " << j <<
" " << hitpatterntime[j] << std::endl);
1068 int priorID = (iSL == 0) ? (priority == 3 ? 0 : 0 + priority) : (priority == 3 ? 5 : 5 + priority);
1069 std::vector<int> BestID(nwires, -1);
1070 std::vector<int> BestLR(nwires, 3);
1071 std::vector<double> BestDriftTime(nwires, expert.getTMax());
1074 for (
int i = 0; i < (int)hitpatterntime.size(); i++) {
1077 for (
int j = 0; j < nwires; j++) {
1078 if ((hitpattern >> i) % 2 == 0 || i == priorID)
1080 if (LRV[i] == 3 && (BestLR[j] != 3))
1082 else if ((LRV[i] != 3 && BestLR[j] == 3) || (HitTimes[i] < BestDriftTime[j])) {
1090 for (
int j = 0; j < nwires - remove_id - 1; j++) {
1091 BestID[nwires - j - 1] = BestID[nwires - j - 2];
1092 BestLR[nwires - j - 1] = BestLR[nwires - j - 2];
1093 BestDriftTime[nwires - j - 1] = BestDriftTime[nwires - j - 2];
1095 BestID[remove_id] = i;
1096 BestLR[remove_id] = LRV[i];
1097 BestDriftTime[remove_id] = HitTimes[i];
1100 for (
int j = 0; j < nwires; j++) {
1101 if (BestID[j] == -1) {
1102 vector<float> tmpvector = {};
1106 for (
int i = 0; i < nwires; i++) {
1108 double deltaPhi = 0;
1111 const int outerpriorList[11] = {4, 4, 4, 2, 2, 0, 1, 1, 3, 3, 3};
1112 const int innerpriorList[15] = {0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4};
1113 const double outerdeltaPhiList[11] = {-1, 0, 1, -0.5, 0.5, 0, -0.5, 0.5, -1, 0, 1};
1114 const double innerdeltaPhiList[15] = {-0.5, 0.5, -1, 0, 1, -1.5, -0.5, 0.5, 1.5, -2, -1, 0, 1, 2};
1116 prior = outerpriorList[BestID[i]];
1117 deltaPhi = outerdeltaPhiList[BestID[i]];
1120 prior = innerpriorList[BestID[i]];
1121 deltaPhi = innerdeltaPhiList[BestID[i]];
1123 B2DEBUG(10,
"BestID:" << BestID[i] <<
"Prior:" << prior <<
"DeltaPhi:" << deltaPhi <<
"Drift Time:" << BestDriftTime[i] <<
1124 "Used Drift Time: " << BestDriftTime[i]*scaleT * (((BestLR[i] >> 1) & 1) - (BestLR[i] & 1)));
1128 inputVector[(3 +
m_AdditionInputPerSL) * iRef + 4 + 4 * i] = BestDriftTime[i] * scaleT * (((BestLR[i] >> 1) & 1) - (BestLR[i] & 1));
1143 vector<float> inputVector;
1144 inputVector.assign(expert.nNodesLayer(0), 0.);
1146 vector<unsigned> nHits;
1149 for (
unsigned ii = 0; ii < hitIds.size(); ++ii) {
1150 int ihit = hitIds[ii];
1152 unsigned short iRef = iSL + 9 * nHits[iSL];
1159 }
else if (t > expert.getTMax()) {
1160 t = expert.getTMax();
1165 vector<float> hitpatterntime =
m_segmentHits[ihit]->gethittime();
1167 HitIDs.assign(hitpatterntime.size(), -1);
1168 vector<float> HitTimes;
1169 HitTimes.assign(hitpatterntime.size(), -1);
1176 float scaleT = pow(2, floor(log2(1. / expert.getTMax())));
1177 inputVector[(3 +
m_AdditionInputPerSL) * iRef + 1] = (((LR >> 1) & 1) - (LR & 1)) * t * scaleT;
1183 B2ERROR(
"Not correct AdditionInputPerSL value for full wire case, please set 11 (TDC only) or 22 (TDC & ADC)");
1184 for (
int j = 0; j < (int) hitpatterntime.size(); j++) {
1185 HitTimes[j] = ((hitpattern >> j) % 2 == 1) ? ((
m_hasT0) ? hitpatterntime[j] -
m_T0 : 0) : -expert.getTMax();
1187 if (HitTimes[j] > expert.getTMax()) HitTimes[j] = expert.getTMax();
1188 if (HitTimes[j] <
m_TMin)HitTimes[j] = -expert.getTMax();
1189 if (HitTimes[j] < 0 && HitTimes[j] >=
m_TMin)HitTimes[j] = 0;
1193 for (
int j = 0; j < 11; j++) {
1198 for (
int j = 0; j < 11; j++) {
1223 vector<float> inputVector;
1224 inputVector.assign(expert.nNodesLayer(0), 0.);
1226 vector<unsigned> nHits;
1228 for (
unsigned ii = 0; ii < hitIds.size(); ++ii) {
1229 int ihit = hitIds[ii];
1231 unsigned short iRef = iSL + 9 * nHits[iSL];
1237 }
else if (t > expert.getTMax()) {
1238 t = expert.getTMax();
1244 inputVector[3 * iRef] = expert.scaleId(relId, iSL);
1245 float scaleT = pow(2, floor(log2(1. / expert.getTMax())));
1246 inputVector[3 * iRef + 1] = (((LR >> 1) & 1) - (LR & 1)) * t * scaleT;
1247 inputVector[3 * iRef + 2] =
m_alpha[iSL][int(priority < 3)] * 0.5;
1256 vector<float> weights = expert.getWeights();
1257 vector<float> layerinput = input;
1258 vector<float> layeroutput = {};
1260 for (
unsigned il = 1; il < expert.nLayers(); ++il) {
1262 layerinput.push_back(1.);
1264 layeroutput.clear();
1265 layeroutput.assign(expert.nNodesLayer(il), 0.);
1267 for (
unsigned io = 0; io < layeroutput.size(); ++io) {
1269 for (
unsigned ii = 0; ii < layerinput.size(); ++ii) {
1270 layeroutput[io] += layerinput[ii] * weights[iw++];
1273 layeroutput[io] = tanh(layeroutput[io] / 2.);
1276 layerinput = layeroutput;
1278 return expert.unscaleTarget(layeroutput);
1288 unsigned dp = precisionInput + precisionWeights - precisionLUT;
1292 vector<long> inputFix(input.size(), 0);
1293 for (
unsigned ii = 0; ii < input.size(); ++ii) {
1294 inputFix[ii] = long(input[ii] * (1 << precisionInput));
1297 vector<float> weights = expert.getWeights();
1298 vector<long> weightsFix(weights.size(), 0);
1299 for (
unsigned iw = 0; iw < weights.size(); ++iw) {
1300 weightsFix[iw] = long(round(weights[iw] * (1 << precisionWeights)));
1303 unsigned xMax = unsigned(ceil(atanh(1. - 1. / (1 << (precisionTanh + 1))) *
1304 (1 << (precisionLUT + 1))));
1307 vector<long> layerinput = inputFix;
1308 vector<long> layeroutput = {};
1310 for (
unsigned il = 1; il < expert.nLayers(); ++il) {
1312 layerinput.push_back(1 << precisionInput);
1314 layeroutput.clear();
1315 layeroutput.assign(expert.nNodesLayer(il), 0);
1317 for (
unsigned io = 0; io < layeroutput.size(); ++io) {
1319 for (
unsigned ii = 0; ii < layerinput.size(); ++ii) {
1320 layeroutput[io] += layerinput[ii] * weightsFix[iw++];
1323 unsigned long bin = abs(layeroutput[io]) >> dp;
1325 float x = (bin + 0.5 - 1. / (1 << (dp + 1))) / (1 << precisionLUT);
1326 long tanhLUT = (bin < xMax) ?
long(round(tanh(x / 2.) * (1 << precisionTanh))) : (1 << precisionTanh);
1327 layeroutput[io] = (layeroutput[io] < 0) ? -tanhLUT : tanhLUT;
1330 layerinput = layeroutput;
1334 vector<float> output(layeroutput.size(), 0.);
1335 for (
unsigned io = 0; io < output.size(); ++io) {
1336 output[io] = layeroutput[io] / float(1 << precisionTanh);
1338 return expert.unscaleTarget(output);
1344 B2INFO(
"Saving networks to file " << filename <<
", array " << arrayname);
1345 TFile datafile(filename.c_str(),
"UPDATE");
1346 TObjArray* MLPs =
new TObjArray(
m_MLPs.size());
1347 for (
unsigned isector = 0; isector <
m_MLPs.size(); ++isector) {
1348 MLPs->Add(&
m_MLPs[isector]);
1350 MLPs->Write(arrayname.c_str(), TObject::kSingleKey | TObject::kOverwrite);
1357 std::ifstream gzipfile(filename, ios_base::in | ios_base::binary);
1358 boost::iostreams::filtering_istream arrayStream;
1359 arrayStream.push(boost::iostreams::gzip_decompressor());
1360 arrayStream.push(gzipfile);
1362 if (gzipfile.is_open()) {
1363 while (arrayStream >> hline) {
1364 for (
unsigned i = 0; i < 18; ++i) {
1365 m_MLPs[hline.exPert].relevantID[i] = hline.relID[i];
1368 }
else {
return false;}
1376 if (filename.size() < 1) {
1379 if (
m_MLPs.size() == 0) {
1380 B2ERROR(
"Could not load Neurotrigger weights from database!");
1384 B2DEBUG(100,
"loaded " <<
m_MLPs.size() <<
" networks from database");
1389 TFile datafile(filename.c_str(),
"READ");
1390 if (!datafile.IsOpen()) {
1391 B2WARNING(
"Could not open file " << filename);
1395 TObjArray* MLPs = (TObjArray*)datafile.Get(arrayname.c_str());
1398 B2WARNING(
"File " << filename <<
" does not contain key " << arrayname);
1402 for (
int isector = 0; isector < MLPs->GetEntriesFast(); ++isector) {
1404 if (expert)
m_MLPs.push_back(*expert);
1405 else B2WARNING(
"Wrong type " << MLPs->At(isector)->ClassName() <<
", ignoring this entry.");
1410 B2DEBUG(100,
"loaded " <<
m_MLPs.size() <<
" networks");
1412 B2INFO(
"Loaded Neurotrigger MLP weights from file: " + filename);
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.
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< 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.
double m_idRef[9][5]
2D phi position of current track scaled to number of wires
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.
double m_radius[9][5]
Radius of the CDC layers with priority wires (2 per super layer)
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.
double m_alpha[9][5]
2D crossing angle of current track
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.
std::vector< float > getInputVectorDefault(unsigned isector, const std::vector< unsigned > &hitIds)
Calculate input values for MLP Default mode.
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.
int m_AdditionWireMode
Switch for addtional input modes.
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.
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.
int m_AdditionInputPerSL
Value for additional input.
int m_TMin
Min Drift time limitation for ETF case only.
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
std::string m_hitCollectionName
Name of the StoreArray containing the input track segment hits.
std::vector< float > getInputVector_fullhit(unsigned isector, const std::vector< unsigned > &hitIds)
Calculate input values for MLP in full hit mode.
std::vector< float > runMLP(unsigned isector, const std::vector< float > &input)
Run an expert MLP.
std::vector< float > getInputVector_extrahit(unsigned isector, const std::vector< unsigned > &hitIds)
Calculate input values for MLP in extra hit mode.
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.
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.