8 #include <framework/logging/Logger.h>
9 #include <trg/cdc/NeuroTrigger.h>
11 #include <cdc/geometry/CDCGeometryPar.h>
12 #include <framework/gearbox/Const.h>
13 #include <framework/gearbox/Unit.h>
14 #include <framework/datastore/StoreObjPtr.h>
15 #include <framework/datastore/StoreArray.h>
16 #include <trg/cdc/dbobjects/CDCTriggerNeuroConfig.h>
17 #include <trg/cdc/dataobjects/CDCTriggerTrack.h>
33 if (p.nHidden.size() != 1 && p.nHidden.size() != p.nMLP) {
34 B2ERROR(
"Number of nHidden lists should be 1 or " << p.nMLP);
37 if (p.outputScale.size() != 1 && p.outputScale.size() != p.nMLP) {
38 B2ERROR(
"Number of outputScale lists should be 1 or " << p.nMLP);
41 bool rangeProduct = (p.phiRange.size() * p.invptRange.size() * p.thetaRange.size() * p.SLpattern.size() == p.nMLP);
43 if (p.phiRange.size() != 1 && p.phiRange.size() != p.nMLP) {
44 B2ERROR(
"Number of phiRange lists should be 1 or " << p.nMLP);
47 if (p.invptRange.size() != 1 && p.invptRange.size() != p.nMLP) {
48 B2ERROR(
"Number of invptRange lists should be 1 or " << p.nMLP);
51 if (p.thetaRange.size() != 1 && p.thetaRange.size() != p.nMLP) {
52 B2ERROR(
"Number of thetaRange lists should be 1 or " << p.nMLP);
55 if (p.SLpattern.size() != 1 && p.SLpattern.size() != p.nMLP) {
56 B2ERROR(
"Number of SLpattern lists should be 1 or " << p.nMLP);
61 if (p.maxHitsPerSL.size() != 1 && p.maxHitsPerSL.size() != p.SLpattern.size()) {
62 B2ERROR(
"Number of maxHitsPerSL lists should be 1 or " << p.SLpattern.size());
65 if (p.SLpatternMask.size() != 1 && p.SLpatternMask.size() != p.SLpattern.size()) {
66 B2ERROR(
"Number of SLpatternMask lists should be 1 or " << p.SLpattern.size());
70 unsigned short nTarget = int(p.targetZ) + int(p.targetTheta);
72 B2ERROR(
"No outputs! Turn on either targetZ or targetTheta.");
76 for (
unsigned iPhi = 0; iPhi < p.phiRange.size(); ++iPhi) {
77 if (p.phiRange[iPhi].size() != 2) {
78 B2ERROR(
"phiRange should be exactly 2 values");
82 if (p.phiRange[iPhi][0] >= p.phiRange[iPhi][1]) {
83 B2ERROR(
"phiRange[0] should be smaller than phiRange[1]");
86 if (p.phiRange[iPhi][0] < -360. || p.phiRange[iPhi][1] > 360. ||
87 (p.phiRange[iPhi][1] - p.phiRange[iPhi][0]) > 360.) {
88 B2ERROR(
"phiRange should be in [-360, 360], with maximal width of 360");
92 for (
unsigned iPt = 0; iPt < p.invptRange.size(); ++iPt) {
93 if (p.invptRange[iPt].size() != 2) {
94 B2ERROR(
"invptRange should be exactly 2 values");
97 if (p.invptRange[iPt][0] >= p.invptRange[iPt][1]) {
98 B2ERROR(
"invptRange[0] should be smaller than invptRange[1]");
102 for (
unsigned iTheta = 0; iTheta < p.thetaRange.size(); ++iTheta) {
103 if (p.thetaRange[iTheta].size() != 2) {
104 B2ERROR(
"thetaRange should be exactly 2 values");
108 if (p.thetaRange[iTheta][0] >= p.thetaRange[iTheta][1]) {
109 B2ERROR(
"thetaRange[0] should be smaller than thetaRange[1]");
112 if (p.thetaRange[iTheta][0] < 0. || p.thetaRange[iTheta][1] > 180.) {
113 B2ERROR(
"thetaRange should be in [0, 180]");
117 for (
unsigned iScale = 0; iScale < p.outputScale.size(); ++iScale) {
118 if (p.outputScale[iScale].size() != 2 * nTarget) {
119 B2ERROR(
"outputScale should be exactly " << 2 * nTarget <<
" values");
124 if (p.phiRange.size() != p.phiRangeTrain.size()) {
125 B2ERROR(
"Number of phiRange lists and phiRangeTrain lists should be equal.");
128 for (
unsigned iPhi = 0; iPhi < p.phiRange.size(); ++iPhi) {
129 if (p.phiRangeTrain[iPhi].size() != 2) {
130 B2ERROR(
"phiRangeTrain should be exactly 2 values.");
132 }
else if (p.phiRangeTrain[iPhi][0] > p.phiRange[iPhi][0] ||
133 p.phiRangeTrain[iPhi][1] < p.phiRange[iPhi][1]) {
134 B2ERROR(
"phiRangeTrain should be wider than phiRange or equal.");
139 if (p.invptRange.size() != p.invptRangeTrain.size()) {
140 B2ERROR(
"Number of invptRange lists and invptRangeTrain lists should be equal.");
143 for (
unsigned iPt = 0; iPt < p.invptRange.size(); ++iPt) {
144 if (p.invptRangeTrain[iPt].size() != 2) {
145 B2ERROR(
"invptRangeTrain should be exactly 2 values.");
147 }
else if (p.invptRangeTrain[iPt][0] > p.invptRange[iPt][0] ||
148 p.invptRangeTrain[iPt][1] < p.invptRange[iPt][1]) {
149 B2ERROR(
"invptRangeTrain should be wider than invptRange or equal.");
154 if (p.thetaRange.size() != p.thetaRangeTrain.size()) {
155 B2ERROR(
"Number of thetaRange lists and thetaRangeTrain lists should be equal.");
158 for (
unsigned iTheta = 0; iTheta < p.thetaRange.size(); ++iTheta) {
159 if (p.thetaRangeTrain[iTheta].size() != 2) {
160 B2ERROR(
"thetaRangeTrain should be exactly 2 values.");
162 }
else if (p.thetaRangeTrain[iTheta][0] > p.thetaRange[iTheta][0] ||
163 p.thetaRangeTrain[iTheta][1] < p.thetaRange[iTheta][1]) {
164 B2ERROR(
"thetaRangeTrain should be wider than thetaRange or equal.");
174 for (
unsigned iMLP = 0; iMLP < p.nMLP; ++iMLP) {
176 vector<unsigned> indices = getRangeIndices(p, iMLP);
178 unsigned short maxHits = (p.maxHitsPerSL.size() == 1) ? p.maxHitsPerSL[0] : p.maxHitsPerSL[indices[3]];
179 unsigned long SLpattern = p.SLpattern[indices[3]];
180 unsigned long SLpatternMask = (p.SLpatternMask.size() == 1) ? p.SLpatternMask[0] : p.SLpatternMask[indices[3]];
181 unsigned short nInput = 27 * maxHits;
182 vector<float> nHidden = (p.nHidden.size() == 1) ? p.nHidden[0] : p.nHidden[iMLP];
183 vector<unsigned short> nNodes = {nInput};
184 for (
unsigned iHid = 0; iHid < nHidden.size(); ++iHid) {
185 if (p.multiplyHidden) {
186 nNodes.push_back(nHidden[iHid] * nNodes[0]);
188 nNodes.push_back(nHidden[iHid]);
191 nNodes.push_back(nTarget);
192 unsigned short targetVars = int(p.targetZ) + (int(p.targetTheta) << 1);
194 vector<float> phiRange = p.phiRangeTrain[indices[0]];
195 vector<float> invptRange = p.invptRangeTrain[indices[1]];
196 vector<float> thetaRange = p.thetaRangeTrain[indices[2]];
197 B2DEBUG(50,
"Ranges for sector " << iMLP
198 <<
": phiRange [" << phiRange[0] <<
", " << phiRange[1]
199 <<
"], invptRange [" << invptRange[0] <<
", " << invptRange[1]
200 <<
"], thetaRange [" << thetaRange[0] <<
", " << thetaRange[1]
201 <<
"], SLpattern " << SLpattern);
203 vector<float> outputScale = (p.outputScale.size() == 1) ? p.outputScale[0] : p.outputScale[iMLP];
210 outputScale[2 * int(p.targetZ)] *=
Unit::deg;
211 outputScale[2 * int(p.targetZ) + 1] *=
Unit::deg;
214 m_MLPs.push_back(
CDCTriggerMLP(nNodes, targetVars, outputScale,
215 phiRange, invptRange, thetaRange,
216 maxHits, SLpattern, SLpatternMask, p.tMax, p.T0fromHits,
226 std::vector<unsigned> indices = {0, 0, 0, 0};
227 if (p.phiRange.size() * p.invptRange.size() * p.thetaRange.size() * p.SLpattern.size() == p.nMLP) {
228 indices[0] = isector % p.phiRange.size();
229 indices[1] = (isector / p.phiRange.size()) % p.invptRange.size();
230 indices[2] = (isector / (p.phiRange.size() * p.invptRange.size())) % p.thetaRange.size();
231 indices[3] = isector / (p.phiRange.size() * p.invptRange.size() * p.thetaRange.size());
233 indices[0] = (p.phiRange.size() == 1) ? 0 : isector;
234 indices[1] = (p.invptRange.size() == 1) ? 0 : isector;
235 indices[2] = (p.thetaRange.size() == 1) ? 0 : isector;
236 indices[3] = (p.SLpattern.size() == 1) ? 0 : isector;
247 for (
int iSL = 0; iSL < 9; ++iSL) {
248 m_TSoffset[iSL] = nTS;
249 nTS += cdc.nWiresInLayer(layerId);
250 m_TSoffset[iSL + 1] = nTS;
251 for (
int priority = 0; priority < 2; ++ priority) {
252 m_radius[iSL][priority] = cdc.senseWireR(layerId + priority);
254 layerId += (iSL > 0 ? 6 : 7);
261 m_segmentHits.isRequired(hitCollectionName);
262 if (!((et_option ==
"fastestpriority") || (et_option ==
"zero") || (et_option ==
"fastest2d"))) {
263 m_eventTime.isRequired(eventTimeName);
265 m_hitCollectionName = hitCollectionName;
271 vector<int> indices = {};
273 if (m_MLPs.size() == 0) {
274 B2WARNING(
"Trying to select MLP before initializing MLPs.");
279 for (
unsigned isector = 0; isector < m_MLPs.size(); ++isector) {
280 if (m_MLPs[isector].inPhiRange(phi0) && m_MLPs[isector].inInvptRange(invpt)
281 && m_MLPs[isector].inThetaRange(theta)) {
282 indices.push_back(isector);
286 if (indices.size() == 0) {
287 B2DEBUG(150,
"Track does not match any sector.");
288 B2DEBUG(150,
"invpt=" << invpt <<
", phi=" << phi0 * 180. / M_PI <<
", theta=" << theta * 180. / M_PI);
298 if (MLPs.size() == 0) {
303 for (
unsigned i = 0; i < MLPs.size(); ++i) {
304 int isector = MLPs[i];
305 unsigned long sectorPattern = m_MLPs[isector].getSLpattern();
306 B2DEBUG(250,
"hitPattern " << pattern <<
" sectorPattern " << sectorPattern);
308 if (sectorPattern == 0) {
309 B2DEBUG(250,
"found match for general sector");
313 if (pattern == sectorPattern) {
314 B2DEBUG(250,
"found match for hit pattern " << pattern);
321 if (neurotrackinputmode) {
322 B2DEBUG(150,
"No sector found to match pattern, using sector 0" << pattern <<
".");
325 B2DEBUG(150,
"No sector found to match pattern " << pattern <<
".");
335 double omega = track.getOmega();
336 for (
int iSL = 0; iSL < 9; ++iSL) {
337 for (
int priority = 0; priority < 2; ++priority) {
338 m_alpha[iSL][priority] = (m_radius[iSL][priority] * abs(omega) < 2.) ?
339 asin(m_radius[iSL][priority] * omega / 2.) :
341 m_idRef[iSL][priority] = remainder(((track.getPhi0() - m_alpha[iSL][priority]) *
342 (m_TSoffset[iSL + 1] - m_TSoffset[iSL]) / 2. / M_PI),
343 (m_TSoffset[iSL + 1] - m_TSoffset[iSL]));
351 unsigned precisionPhi = m_precision[0];
352 unsigned precisionAlpha = m_precision[0];
353 unsigned precisionScale = m_precision[1];
354 unsigned precisionId = m_precision[2];
356 double omega = track.getOmega();
357 long phi = round(track.getPhi0() * (1 << precisionPhi));
359 for (
int iSL = 0; iSL < 9; ++iSL) {
360 for (
int priority = 0; priority < 2; ++priority) {
362 m_alpha[iSL][priority] =
363 (m_radius[iSL][priority] * abs(omega) < 2) ?
364 round(asin(m_radius[iSL][priority] * omega / 2) * (1 << precisionAlpha)) :
365 round(M_PI_2 * (1 << precisionAlpha));
366 long dphi = (precisionAlpha >= precisionPhi) ?
367 phi - (
long(m_alpha[iSL][priority]) >> (precisionAlpha - precisionPhi)) :
368 phi - (long(m_alpha[iSL][priority]) << (precisionPhi - precisionAlpha));
369 m_idRef[iSL][priority] =
370 long(dphi * round((m_TSoffset[iSL + 1] - m_TSoffset[iSL]) / 2. / M_PI * (1 << precisionScale)) /
371 (
long(1) << (precisionPhi + precisionScale - precisionId)));
373 m_alpha[iSL][priority] /= (1 << precisionAlpha);
374 m_idRef[iSL][priority] /= (1 << precisionId);
382 int iSL = hit.getISuperLayer();
383 int priority = hit.getPriorityPosition();
385 double relId = hit.getSegmentID() + 0.5 * (((priority >> 1) & 1) - (priority & 1))
386 - m_TSoffset[iSL] - m_idRef[iSL][int(priority < 3)];
387 relId = remainder(relId, (m_TSoffset[iSL + 1] - m_TSoffset[iSL]));
396 B2DEBUG(200,
"looping over axials:");
397 for (
unsigned ihit = 0; ihit < Hits.
size(); ++ihit) {
399 if (Hits.
weight(ihit) < 0)
continue;
400 unsigned short iSL = Hits[ihit]->getISuperLayer();
401 if (iSL % 2 == 1 && onlyAxials) {
continue;}
403 B2DEBUG(200,
" check drifttime: SL" + std::to_string(iSL) +
",ID = " + std::to_string(Hits[ihit]->getSegmentID()) +
", t = " +
404 std::to_string(Hits[ihit]->priorityTime()));
405 double relId = getRelId(*Hits[ihit]);
406 if (m_MLPs[isector].isRelevant(relId, iSL) &&
407 Hits[ihit]->priorityTime() < tlow) {
408 tlow = Hits[ihit]->priorityTime();
409 B2DEBUG(200,
" new tlow: " << std::to_string(tlow));
420 if (et_option != m_MLPs[isector].get_et_option()) {
421 B2WARNING(
"Used event time option is different to the one set in the MLP"
422 <<
LogVar(
"et_option", et_option) <<
LogVar(
"isector", isector)
423 <<
LogVar(
"et_option_mlp", m_MLPs[isector].get_et_option()));
425 if (et_option ==
"fastestpriority") {
426 B2DEBUG(200,
"et_option is 'fastestpriority'");
431 m_T0 = getLowestTime(isector, Hits,
false);
439 }
else if (et_option ==
"fastest2d") {
444 m_T0 = getLowestTime(isector, Hits,
true);
451 }
else if (et_option ==
"zero") {
454 }
else if (et_option ==
"etf_only") {
455 bool hasT0 = (m_eventTime.isValid()) ? m_eventTime->hasBinnedEventT0(Const::CDC) :
false;
457 m_T0 = m_eventTime->getBinnedEventT0(Const::CDC);
460 B2ERROR(
"No ETF output, but forced to use ETF!");
464 }
else if (et_option ==
"etf_or_fastestpriority") {
465 bool hasT0 = (m_eventTime.isValid()) ? m_eventTime->hasBinnedEventT0(Const::CDC) :
false;
467 m_T0 = m_eventTime->getBinnedEventT0(Const::CDC);
470 getEventTime(isector, track,
"fastestpriority", neuroinputmode);
484 }
else if (et_option ==
"etf_or_fastest2d") {
485 bool hasT0 = (m_eventTime.isValid()) ? m_eventTime->hasBinnedEventT0(Const::CDC) :
false;
487 m_T0 = m_eventTime->getBinnedEventT0(Const::CDC);
490 getEventTime(isector, track,
"fastest2d", neuroinputmode);
504 }
else if (et_option ==
"etf_or_zero") {
505 bool hasT0 = (m_eventTime.isValid()) ? m_eventTime->hasBinnedEventT0(Const::CDC) :
false;
507 m_T0 = m_eventTime->getBinnedEventT0(Const::CDC);
513 }
else if (et_option ==
"etfcc") {
514 if (!neuroinputmode) {
515 B2ERROR(
"cannot use 'etfcc' timing option without hw tracks!");
517 if (track.getHasETFTime()) {
518 m_T0 = track.getETF_unpacked();
525 }
else if (et_option ==
"etfcc_or_zero") {
526 if (!neuroinputmode) {
527 B2ERROR(
"cannot use 'etfcc' timing option without hw tracks!");
529 if (track.getHasETFTime()) {
530 m_T0 = track.getETF_unpacked();
537 }
else if (et_option ==
"etfcc_or_fastestpriority") {
538 if (!neuroinputmode) {
539 B2ERROR(
"cannot use 'etfcc' timing option without hw tracks!");
541 if (track.getHasETFTime()) {
542 m_T0 = track.getETF_unpacked();
545 getEventTime(isector, track,
"fastestpriority", neuroinputmode);
548 }
else if (et_option ==
"etfhwin") {
549 if (!neuroinputmode) {
550 B2ERROR(
"cannot use 'etfcc' timing option without hw tracks!");
552 m_T0 = track.getETF_recalced();
556 B2ERROR(
"No valid parameter for et_option (" << et_option <<
" )!");
563 B2WARNING(
"This function is deprecated, it used the flag 'T0fromHits'. "
564 <<
"Give additionally et_option as argument to use the new function. "
565 <<
"et_option is now set for T0fromHits=True to 'etf_fastestpriority' "
566 <<
"and for T0fromHits=false to 'etf_or_zero'.");
567 if (m_MLPs[isector].getT0fromHits()) {
568 getEventTime(isector, track,
"etf_or_fastestpriority");
570 getEventTime(isector, track,
"etf_or_zero");
578 unsigned long driftth = 0;
579 vector<unsigned> nHits;
584 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ ihit) {
586 if (axialHits.
weight(ihit) < 0) {
589 unsigned short iSL = axialHits[ihit]->getISuperLayer();
591 if ((!neurotrackinputmode) && (iSL % 2 == 1))
continue;
593 int t = (m_hasT0) ? axialHits[ihit]->priorityTime() - m_T0 : 0;
594 double relId = getRelId(*axialHits[ihit]);
595 if (t < 0 || t > expert.getTMax()) {
596 if (expert.isRelevant(relId, iSL)) {
597 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
598 driftth |= 1 << (8 - iSL + 9 * nHits[iSL]);
604 if (!neurotrackinputmode) {
606 for (
int ihit = 0; ihit < m_segmentHits.getEntries(); ++ ihit) {
607 unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
609 if (iSL % 2 == 0)
continue;
611 int t = (m_hasT0) ? m_segmentHits[ihit]->priorityTime() - m_T0 : 0;
612 double relId = getRelId(*m_segmentHits[ihit]);
613 if (t < 0 || t > expert.getTMax()) {
614 if (expert.isRelevant(relId, iSL)) {
615 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
616 driftth |= 1 << (8 - iSL + 9 * nHits[iSL]);
628 unsigned long chitPattern = 0;
629 vector<unsigned> nHits;
634 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ ihit) {
636 if (axialHits.
weight(ihit) < 0) {
639 unsigned short iSL = axialHits[ihit]->getISuperLayer();
641 if ((!neurotrackinputmode) && (iSL % 2 == 1))
continue;
642 double relId = getRelId(*axialHits[ihit]);
643 if (expert.isRelevant(relId, iSL)) {
644 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
645 chitPattern |= 1 << (iSL + 9 * nHits[iSL]);
650 if (!neurotrackinputmode) {
652 for (
int ihit = 0; ihit < m_segmentHits.getEntries(); ++ ihit) {
653 unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
655 if (iSL % 2 == 0)
continue;
657 double relId = getRelId(*m_segmentHits[ihit]);
658 if (expert.isRelevant(relId, iSL)) {
659 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
660 chitPattern |= 1 << (iSL + 9 * nHits[iSL]);
673 unsigned long hitPattern = 0;
674 vector<unsigned> nHits;
679 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ ihit) {
681 if (axialHits.
weight(ihit) < 0) {
684 unsigned short iSL = axialHits[ihit]->getISuperLayer();
686 if ((!neurotrackinputmode) && (iSL % 2 == 1))
continue;
688 int t = (m_hasT0) ? axialHits[ihit]->priorityTime() - m_T0 : 0;
691 }
else if (t > expert.getTMax()) {
692 t = expert.getTMax();
694 double relId = getRelId(*axialHits[ihit]);
696 if (expert.isRelevant(relId, iSL)) {
697 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
698 hitPattern |= 1 << (iSL + 9 * nHits[iSL]);
701 B2DEBUG(250,
"hit in SL " << iSL);
703 B2DEBUG(250,
"hit in SL " << iSL <<
" not relevant (relId = " << relId <<
")");
706 if (!neurotrackinputmode) {
708 for (
int ihit = 0; ihit < m_segmentHits.getEntries(); ++ ihit) {
709 unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
711 if (iSL % 2 == 0)
continue;
713 int t = (m_hasT0) ? m_segmentHits[ihit]->priorityTime() - m_T0 : 0;
716 }
else if (t > expert.getTMax()) {
717 t = expert.getTMax();
719 double relId = getRelId(*m_segmentHits[ihit]);
720 if (expert.isRelevant(relId, iSL)) {
721 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
722 hitPattern |= 1 << (iSL + 9 * nHits[iSL]);
725 B2DEBUG(250,
"hit in SL " << iSL);
727 B2DEBUG(250,
"hit in SL " << iSL <<
" not relevant (relId = " << relId <<
")");
731 B2DEBUG(250,
"hitPattern " << hitPattern);
732 return hitPattern & expert.getSLpatternMask();
739 vector<unsigned> selectedHitIds = {};
742 tMin.assign(expert.nNodesLayer(0), expert.getTMax());
743 vector<bool> LRknown;
744 LRknown.assign(expert.nNodesLayer(0),
false);
746 hitIds.assign(expert.nNodesLayer(0), -1);
747 vector<unsigned> nHits;
753 B2DEBUG(250,
"start hit loop over all related hits");
758 for (
unsigned ihit = 0; ihit < allHits.
size(); ++ihit) {
760 if (allHits.
weight(ihit) < 0)
continue;
761 unsigned short iSL = allHits[ihit]->getISuperLayer();
762 if (expert.getSLpatternUnmasked() != 0 &&
763 !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
764 B2DEBUG(250,
"skipping hit in SL " << iSL);
768 int t = (m_hasT0) ? allHits[ihit]->priorityTime() - m_T0 : 0;
771 }
else if (t > expert.getTMax()) {
772 t = expert.getTMax();
774 double relId = getRelId(*allHits[ihit]);
775 if (expert.isRelevant(relId, iSL)) {
777 unsigned short iRef = iSL;
778 if (expert.getMaxHitsPerSL() > 1) {
779 if (nHits[iSL] < expert.getMaxHitsPerSL() &&
780 (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
781 iRef += 9 * nHits[iSL];
785 if ((LRknown[iRef] && !LRknown[
compare]) ||
786 (LRknown[iRef] == LRknown[
compare] && tMin[iRef] < tMin[
compare]))
794 useHit = (allHits[ihit]->LRknown() && t <= tMin[iRef]);
796 useHit = (allHits[ihit]->LRknown() || t <= tMin[iRef]);
798 B2DEBUG(250,
"relevant wire SL " << iSL <<
" LR " << allHits[ihit]->getLeftRight()
799 <<
" t " << t <<
" iRef " << iRef <<
" useHit " << useHit);
802 LRknown[iRef] = allHits[ihit]->LRknown();
804 hitIds[iRef] = allHits[ihit]->getArrayIndex();
809 for (
unsigned iHit = 0; iHit < hitIds.size(); ++iHit) {
810 if (hitIds[iHit] >= 0) selectedHitIds.push_back(hitIds[iHit]);
812 return selectedHitIds;
816 bool returnAllRelevant)
819 vector<unsigned> selectedHitIds = {};
822 tMin.assign(expert.nNodesLayer(0), expert.getTMax());
823 vector<bool> LRknown;
824 LRknown.assign(expert.nNodesLayer(0),
false);
826 hitIds.assign(expert.nNodesLayer(0), -1);
827 vector<unsigned> nHits;
833 B2DEBUG(250,
"start axial hit loop");
834 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ihit) {
836 if (axialHits.
weight(ihit) < 0)
continue;
837 unsigned short iSL = axialHits[ihit]->getISuperLayer();
839 if (iSL % 2 == 1)
continue;
840 if (expert.getSLpatternUnmasked() != 0 &&
841 !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
842 B2DEBUG(250,
"skipping hit in SL " << iSL);
847 int t = (m_hasT0) ? axialHits[ihit]->priorityTime() - m_T0 : 0;
850 }
else if (t > expert.getTMax()) {
851 t = expert.getTMax();
853 double relId = getRelId(*axialHits[ihit]);
854 if (expert.isRelevant(relId, iSL)) {
856 unsigned short iRef = iSL;
857 if (expert.getMaxHitsPerSL() > 1) {
858 if (nHits[iSL] < expert.getMaxHitsPerSL() &&
859 (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
860 iRef += 9 * nHits[iSL];
864 if ((LRknown[iRef] && !LRknown[
compare]) ||
865 (LRknown[iRef] == LRknown[
compare] && tMin[iRef] < tMin[
compare]))
873 useHit = (axialHits[ihit]->LRknown() && t <= tMin[iRef]);
875 useHit = (axialHits[ihit]->LRknown() || t <= tMin[iRef]);
877 B2DEBUG(250,
"relevant wire SL " << iSL <<
" LR " << axialHits[ihit]->getLeftRight()
878 <<
" t " << t <<
" iRef " << iRef <<
" useHit " << useHit);
881 LRknown[iRef] = axialHits[ihit]->LRknown();
883 hitIds[iRef] = axialHits[ihit]->getArrayIndex();
885 if (returnAllRelevant) selectedHitIds.push_back(axialHits[ihit]->getArrayIndex());
890 B2DEBUG(250,
"start stereo hit loop");
891 for (
int ihit = 0; ihit < m_segmentHits.getEntries(); ++ ihit) {
892 unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
894 if (iSL % 2 == 0)
continue;
895 if (expert.getSLpatternUnmasked() != 0 &&
896 !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
897 B2DEBUG(250,
"skipping hit in SL " << iSL);
901 int t = (m_hasT0) ? m_segmentHits[ihit]->priorityTime() - m_T0 : 0;
904 }
else if (t > expert.getTMax()) {
905 t = expert.getTMax();
907 double relId = getRelId(*m_segmentHits[ihit]);
908 if (expert.isRelevant(relId, iSL)) {
910 unsigned short iRef = iSL;
911 if (expert.getMaxHitsPerSL() > 1) {
912 if (nHits[iSL] < expert.getMaxHitsPerSL() &&
913 (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
914 iRef += 9 * nHits[iSL];
918 if ((LRknown[iRef] && !LRknown[
compare]) ||
919 (LRknown[iRef] == LRknown[
compare] && tMin[iRef] < tMin[
compare]))
927 useHit = (m_segmentHits[ihit]->LRknown() && t <= tMin[iRef]);
929 useHit = (m_segmentHits[ihit]->LRknown() || t <= tMin[iRef]);
931 B2DEBUG(250,
"relevant wire SL " << iSL <<
" LR " << m_segmentHits[ihit]->getLeftRight()
932 <<
" t " << t <<
" iRef " << iRef <<
" useHit " << useHit);
935 LRknown[iRef] = m_segmentHits[ihit]->LRknown();
939 if (returnAllRelevant) selectedHitIds.push_back(ihit);
944 if (!returnAllRelevant) {
945 for (
unsigned iHit = 0; iHit < hitIds.size(); ++iHit) {
946 if (hitIds[iHit] >= 0) selectedHitIds.push_back(hitIds[iHit]);
949 return selectedHitIds;
957 vector<float> inputVector;
958 inputVector.assign(expert.nNodesLayer(0), 0.);
960 vector<unsigned> nHits;
962 for (
unsigned ii = 0; ii < hitIds.size(); ++ii) {
963 int ihit = hitIds[ii];
964 unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
965 unsigned short iRef = iSL + 9 * nHits[iSL];
967 int priot = m_segmentHits[ihit]->priorityTime();
968 int t = (m_hasT0) ? priot - m_T0 : 0;
970 t = expert.getTMax();
971 }
else if (t > expert.getTMax()) {
972 t = expert.getTMax();
974 int LR = m_segmentHits[ihit]->getLeftRight();
975 double relId = getRelId(*m_segmentHits[ihit]);
976 int priority = m_segmentHits[ihit]->getPriorityPosition();
978 inputVector[3 * iRef] = expert.scaleId(relId, iSL);
979 float scaleT = pow(2, floor(log2(1. / expert.getTMax())));
980 inputVector[3 * iRef + 1] = (((LR >> 1) & 1) - (LR & 1)) * t * scaleT;
981 inputVector[3 * iRef + 2] = m_alpha[iSL][int(priority < 3)] * 0.5;
990 vector<float> weights = expert.getWeights();
991 vector<float> layerinput = input;
992 vector<float> layeroutput = {};
994 for (
unsigned il = 1; il < expert.nLayers(); ++il) {
996 layerinput.push_back(1.);
999 layeroutput.assign(expert.nNodesLayer(il), 0.);
1001 for (
unsigned io = 0; io < layeroutput.size(); ++io) {
1003 for (
unsigned ii = 0; ii < layerinput.size(); ++ii) {
1004 layeroutput[io] += layerinput[ii] * weights[iw++];
1007 layeroutput[io] = tanh(layeroutput[io] / 2.);
1010 layerinput = layeroutput;
1012 return expert.unscaleTarget(layeroutput);
1018 unsigned precisionInput = m_precision[3];
1019 unsigned precisionWeights = m_precision[4];
1020 unsigned precisionLUT = m_precision[5];
1021 unsigned precisionTanh = m_precision[3];
1022 unsigned dp = precisionInput + precisionWeights - precisionLUT;
1026 vector<long> inputFix(input.size(), 0);
1027 for (
unsigned ii = 0; ii < input.size(); ++ii) {
1028 inputFix[ii] = long(input[ii] * (1 << precisionInput));
1031 vector<float> weights = expert.getWeights();
1032 vector<long> weightsFix(weights.size(), 0);
1033 for (
unsigned iw = 0; iw < weights.size(); ++iw) {
1034 weightsFix[iw] = long(round(weights[iw] * (1 << precisionWeights)));
1037 unsigned xMax = unsigned(ceil(atanh(1. - 1. / (1 << (precisionTanh + 1))) *
1038 (1 << (precisionLUT + 1))));
1041 vector<long> layerinput = inputFix;
1042 vector<long> layeroutput = {};
1044 for (
unsigned il = 1; il < expert.nLayers(); ++il) {
1046 layerinput.push_back(1 << precisionInput);
1048 layeroutput.clear();
1049 layeroutput.assign(expert.nNodesLayer(il), 0);
1051 for (
unsigned io = 0; io < layeroutput.size(); ++io) {
1053 for (
unsigned ii = 0; ii < layerinput.size(); ++ii) {
1054 layeroutput[io] += layerinput[ii] * weightsFix[iw++];
1057 unsigned long bin = abs(layeroutput[io]) >> dp;
1059 float x = (bin + 0.5 - 1. / (1 << (dp + 1))) / (1 << precisionLUT);
1060 long tanhLUT = (bin < xMax) ?
long(round(tanh(x / 2.) * (1 << precisionTanh))) : (1 << precisionTanh);
1061 layeroutput[io] = (layeroutput[io] < 0) ? -tanhLUT : tanhLUT;
1064 layerinput = layeroutput;
1068 vector<float> output(layeroutput.size(), 0.);
1069 for (
unsigned io = 0; io < output.size(); ++io) {
1070 output[io] = layeroutput[io] / float(1 << precisionTanh);
1072 return expert.unscaleTarget(output);
1078 B2INFO(
"Saving networks to file " << filename <<
", array " << arrayname);
1079 TFile datafile(filename.c_str(),
"UPDATE");
1080 TObjArray* MLPs =
new TObjArray(m_MLPs.size());
1081 for (
unsigned isector = 0; isector < m_MLPs.size(); ++isector) {
1082 MLPs->Add(&m_MLPs[isector]);
1084 MLPs->Write(arrayname.c_str(), TObject::kSingleKey | TObject::kOverwrite);
1093 if (filename.size() < 1) {
1095 m_MLPs = m_cdctriggerneuroconfig->getMLPs();
1096 if (m_MLPs.size() == 0) {
1097 B2ERROR(
"Could not load Neurotrigger weights from database!");
1100 B2DEBUG(2,
"Loaded Neurotrigger MLP weights from database: " + m_cdctriggerneuroconfig->getNNName());
1101 B2DEBUG(100,
"loaded " << m_MLPs.size() <<
" networks from database");
1106 TFile datafile(filename.c_str(),
"READ");
1107 if (!datafile.IsOpen()) {
1108 B2WARNING(
"Could not open file " << filename);
1112 TObjArray* MLPs = (TObjArray*)datafile.Get(arrayname.c_str());
1115 B2WARNING(
"File " << filename <<
" does not contain key " << arrayname);
1119 for (
int isector = 0; isector < MLPs->GetEntriesFast(); ++isector) {
1121 if (expert) m_MLPs.push_back(*expert);
1122 else B2WARNING(
"Wrong type " << MLPs->At(isector)->ClassName() <<
", ignoring this entry.");
1127 B2DEBUG(100,
"loaded " << m_MLPs.size() <<
" networks");
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...
double getRelId(const CDCTriggerSegmentHit &hit)
Calculate phi position of a hit relative to 2D track (scaled to number of wires).
void initialize(const Parameters &p)
Set parameters and get some network independent parameters.
std::vector< int > selectMLPs(float phi0, float invpt, float theta)
Select all matching expert MLPs based on the given track parameters.
void updateTrack(const CDCTriggerTrack &track)
Calculate 2D phi position and arclength for the given track and store them.
bool load(const std::string &filename, const std::string &arrayname="MLPs")
Load MLPs from file.
std::vector< unsigned > selectHits(unsigned isector, const CDCTriggerTrack &track, bool returnAllRelevant=false)
Select best hits for each super layer.
std::vector< float > runMLPFix(unsigned isector, std::vector< float > input)
Run an expert MLP with fixed point arithmetic.
void initializeCollections(std::string hitCollectionName, std::string eventTimeName, const std::string &et_option)
set the hit collection and event time to required and store the hit collection name
std::vector< float > getInputVector(unsigned isector, const std::vector< unsigned > &hitIds)
Calculate input values for MLP.
int selectMLPbyPattern(std::vector< int > &MLPs, unsigned long pattern, const bool neurotrackinputmode)
Select one MLP from a list of sector indices.
unsigned long getInputPattern(unsigned isector, const CDCTriggerTrack &track, const bool neurotrackinputmode)
Calculate input pattern for MLP.
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.
void setConstants()
Loads parameters from the geometry and precalculates some constants that will be needed.
std::vector< unsigned > getRangeIndices(const Parameters &p, unsigned isector)
Get indices for sector ranges in parameter lists.
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
std::vector< float > runMLP(unsigned isector, const std::vector< float > &input)
Run an expert MLP.
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.
Struct to keep neurotrigger parameters.