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>
32 if (p.nHidden.size() != 1 && p.nHidden.size() != p.nMLP) {
33 B2ERROR(
"Number of nHidden lists should be 1 or " << p.nMLP);
36 if (p.outputScale.size() != 1 && p.outputScale.size() != p.nMLP) {
37 B2ERROR(
"Number of outputScale lists should be 1 or " << p.nMLP);
40 bool rangeProduct = (p.phiRange.size() * p.invptRange.size() * p.thetaRange.size() * p.SLpattern.size() == p.nMLP);
42 if (p.phiRange.size() != 1 && p.phiRange.size() != p.nMLP) {
43 B2ERROR(
"Number of phiRange lists should be 1 or " << p.nMLP);
46 if (p.invptRange.size() != 1 && p.invptRange.size() != p.nMLP) {
47 B2ERROR(
"Number of invptRange lists should be 1 or " << p.nMLP);
50 if (p.thetaRange.size() != 1 && p.thetaRange.size() != p.nMLP) {
51 B2ERROR(
"Number of thetaRange lists should be 1 or " << p.nMLP);
54 if (p.SLpattern.size() != 1 && p.SLpattern.size() != p.nMLP) {
55 B2ERROR(
"Number of SLpattern lists should be 1 or " << p.nMLP);
60 if (p.maxHitsPerSL.size() != 1 && p.maxHitsPerSL.size() != p.SLpattern.size()) {
61 B2ERROR(
"Number of maxHitsPerSL lists should be 1 or " << p.SLpattern.size());
64 if (p.SLpatternMask.size() != 1 && p.SLpatternMask.size() != p.SLpattern.size()) {
65 B2ERROR(
"Number of SLpatternMask lists should be 1 or " << p.SLpattern.size());
69 unsigned short nTarget = int(p.targetZ) + int(p.targetTheta);
71 B2ERROR(
"No outputs! Turn on either targetZ or targetTheta.");
75 for (
unsigned iPhi = 0; iPhi < p.phiRange.size(); ++iPhi) {
76 if (p.phiRange[iPhi].size() != 2) {
77 B2ERROR(
"phiRange should be exactly 2 values");
81 if (p.phiRange[iPhi][0] >= p.phiRange[iPhi][1]) {
82 B2ERROR(
"phiRange[0] should be smaller than phiRange[1]");
85 if (p.phiRange[iPhi][0] < -360. || p.phiRange[iPhi][1] > 360. ||
86 (p.phiRange[iPhi][1] - p.phiRange[iPhi][0]) > 360.) {
87 B2ERROR(
"phiRange should be in [-360, 360], with maximal width of 360");
91 for (
unsigned iPt = 0; iPt < p.invptRange.size(); ++iPt) {
92 if (p.invptRange[iPt].size() != 2) {
93 B2ERROR(
"invptRange should be exactly 2 values");
96 if (p.invptRange[iPt][0] >= p.invptRange[iPt][1]) {
97 B2ERROR(
"invptRange[0] should be smaller than invptRange[1]");
101 for (
unsigned iTheta = 0; iTheta < p.thetaRange.size(); ++iTheta) {
102 if (p.thetaRange[iTheta].size() != 2) {
103 B2ERROR(
"thetaRange should be exactly 2 values");
107 if (p.thetaRange[iTheta][0] >= p.thetaRange[iTheta][1]) {
108 B2ERROR(
"thetaRange[0] should be smaller than thetaRange[1]");
111 if (p.thetaRange[iTheta][0] < 0. || p.thetaRange[iTheta][1] > 180.) {
112 B2ERROR(
"thetaRange should be in [0, 180]");
116 for (
unsigned iScale = 0; iScale < p.outputScale.size(); ++iScale) {
117 if (p.outputScale[iScale].size() != 2 * nTarget) {
118 B2ERROR(
"outputScale should be exactly " << 2 * nTarget <<
" values");
123 if (p.phiRange.size() != p.phiRangeTrain.size()) {
124 B2ERROR(
"Number of phiRange lists and phiRangeTrain lists should be equal.");
127 for (
unsigned iPhi = 0; iPhi < p.phiRange.size(); ++iPhi) {
128 if (p.phiRangeTrain[iPhi].size() != 2) {
129 B2ERROR(
"phiRangeTrain should be exactly 2 values.");
131 }
else if (p.phiRangeTrain[iPhi][0] > p.phiRange[iPhi][0] ||
132 p.phiRangeTrain[iPhi][1] < p.phiRange[iPhi][1]) {
133 B2ERROR(
"phiRangeTrain should be wider than phiRange or equal.");
138 if (p.invptRange.size() != p.invptRangeTrain.size()) {
139 B2ERROR(
"Number of invptRange lists and invptRangeTrain lists should be equal.");
142 for (
unsigned iPt = 0; iPt < p.invptRange.size(); ++iPt) {
143 if (p.invptRangeTrain[iPt].size() != 2) {
144 B2ERROR(
"invptRangeTrain should be exactly 2 values.");
146 }
else if (p.invptRangeTrain[iPt][0] > p.invptRange[iPt][0] ||
147 p.invptRangeTrain[iPt][1] < p.invptRange[iPt][1]) {
148 B2ERROR(
"invptRangeTrain should be wider than invptRange or equal.");
153 if (p.thetaRange.size() != p.thetaRangeTrain.size()) {
154 B2ERROR(
"Number of thetaRange lists and thetaRangeTrain lists should be equal.");
157 for (
unsigned iTheta = 0; iTheta < p.thetaRange.size(); ++iTheta) {
158 if (p.thetaRangeTrain[iTheta].size() != 2) {
159 B2ERROR(
"thetaRangeTrain should be exactly 2 values.");
161 }
else if (p.thetaRangeTrain[iTheta][0] > p.thetaRange[iTheta][0] ||
162 p.thetaRangeTrain[iTheta][1] < p.thetaRange[iTheta][1]) {
163 B2ERROR(
"thetaRangeTrain should be wider than thetaRange or equal.");
173 for (
unsigned iMLP = 0; iMLP < p.nMLP; ++iMLP) {
175 vector<unsigned> indices = getRangeIndices(p, iMLP);
177 unsigned short maxHits = (p.maxHitsPerSL.size() == 1) ? p.maxHitsPerSL[0] : p.maxHitsPerSL[indices[3]];
178 unsigned long SLpattern = p.SLpattern[indices[3]];
179 unsigned long SLpatternMask = (p.SLpatternMask.size() == 1) ? p.SLpatternMask[0] : p.SLpatternMask[indices[3]];
180 unsigned short nInput = 27 * maxHits;
181 vector<float> nHidden = (p.nHidden.size() == 1) ? p.nHidden[0] : p.nHidden[iMLP];
182 vector<unsigned short> nNodes = {nInput};
183 for (
unsigned iHid = 0; iHid < nHidden.size(); ++iHid) {
184 if (p.multiplyHidden) {
185 nNodes.push_back(nHidden[iHid] * nNodes[0]);
187 nNodes.push_back(nHidden[iHid]);
190 nNodes.push_back(nTarget);
191 unsigned short targetVars = int(p.targetZ) + (int(p.targetTheta) << 1);
193 vector<float> phiRange = p.phiRangeTrain[indices[0]];
194 vector<float> invptRange = p.invptRangeTrain[indices[1]];
195 vector<float> thetaRange = p.thetaRangeTrain[indices[2]];
196 B2DEBUG(50,
"Ranges for sector " << iMLP
197 <<
": phiRange [" << phiRange[0] <<
", " << phiRange[1]
198 <<
"], invptRange [" << invptRange[0] <<
", " << invptRange[1]
199 <<
"], thetaRange [" << thetaRange[0] <<
", " << thetaRange[1]
200 <<
"], SLpattern " << SLpattern);
202 vector<float> outputScale = (p.outputScale.size() == 1) ? p.outputScale[0] : p.outputScale[iMLP];
209 outputScale[2 * int(p.targetZ)] *=
Unit::deg;
210 outputScale[2 * int(p.targetZ) + 1] *=
Unit::deg;
213 m_MLPs.push_back(
CDCTriggerMLP(nNodes, targetVars, outputScale,
214 phiRange, invptRange, thetaRange,
215 maxHits, SLpattern, SLpatternMask, p.tMax, p.T0fromHits,
225 std::vector<unsigned> indices = {0, 0, 0, 0};
226 if (p.phiRange.size() * p.invptRange.size() * p.thetaRange.size() * p.SLpattern.size() == p.nMLP) {
227 indices[0] = isector % p.phiRange.size();
228 indices[1] = (isector / p.phiRange.size()) % p.invptRange.size();
229 indices[2] = (isector / (p.phiRange.size() * p.invptRange.size())) % p.thetaRange.size();
230 indices[3] = isector / (p.phiRange.size() * p.invptRange.size() * p.thetaRange.size());
232 indices[0] = (p.phiRange.size() == 1) ? 0 : isector;
233 indices[1] = (p.invptRange.size() == 1) ? 0 : isector;
234 indices[2] = (p.thetaRange.size() == 1) ? 0 : isector;
235 indices[3] = (p.SLpattern.size() == 1) ? 0 : isector;
246 for (
int iSL = 0; iSL < 9; ++iSL) {
247 m_TSoffset[iSL] = nTS;
248 nTS += cdc.nWiresInLayer(layerId);
249 m_TSoffset[iSL + 1] = nTS;
250 for (
int priority = 0; priority < 2; ++ priority) {
251 m_radius[iSL][priority] = cdc.senseWireR(layerId + priority);
253 layerId += (iSL > 0 ? 6 : 7);
260 m_segmentHits.isRequired(hitCollectionName);
261 if (!((et_option ==
"fastestpriority") || (et_option ==
"zero") || (et_option ==
"fastest2d"))) {
262 m_eventTime.isRequired(eventTimeName);
264 m_hitCollectionName = hitCollectionName;
270 vector<int> indices = {};
272 if (m_MLPs.size() == 0) {
273 B2WARNING(
"Trying to select MLP before initializing MLPs.");
278 for (
unsigned isector = 0; isector < m_MLPs.size(); ++isector) {
279 if (m_MLPs[isector].inPhiRange(phi0) && m_MLPs[isector].inInvptRange(invpt)
280 && m_MLPs[isector].inThetaRange(theta)) {
281 indices.push_back(isector);
285 if (indices.size() == 0) {
286 B2DEBUG(150,
"Track does not match any sector.");
287 B2DEBUG(150,
"invpt=" << invpt <<
", phi=" << phi0 * 180. / M_PI <<
", theta=" << theta * 180. / M_PI);
297 if (MLPs.size() == 0) {
302 for (
unsigned i = 0; i < MLPs.size(); ++i) {
303 int isector = MLPs[i];
304 unsigned long sectorPattern = m_MLPs[isector].getSLpattern();
305 B2DEBUG(250,
"hitPattern " << pattern <<
" sectorPattern " << sectorPattern);
307 if (sectorPattern == 0) {
308 B2DEBUG(250,
"found match for general sector");
312 if (pattern == sectorPattern) {
313 B2DEBUG(250,
"found match for hit pattern " << pattern);
320 if (neurotrackinputmode) {
321 B2DEBUG(150,
"No sector found to match pattern, using sector 0" << pattern <<
".");
324 B2DEBUG(150,
"No sector found to match pattern " << pattern <<
".");
334 double omega = track.getOmega();
335 for (
int iSL = 0; iSL < 9; ++iSL) {
336 for (
int priority = 0; priority < 2; ++priority) {
337 m_alpha[iSL][priority] = (m_radius[iSL][priority] * abs(omega) < 2.) ?
338 asin(m_radius[iSL][priority] * omega / 2.) :
340 m_idRef[iSL][priority] = remainder(((track.getPhi0() - m_alpha[iSL][priority]) *
341 (m_TSoffset[iSL + 1] - m_TSoffset[iSL]) / 2. / M_PI),
342 (m_TSoffset[iSL + 1] - m_TSoffset[iSL]));
350 unsigned precisionPhi = m_precision[0];
351 unsigned precisionAlpha = m_precision[0];
352 unsigned precisionScale = m_precision[1];
353 unsigned precisionId = m_precision[2];
355 double omega = track.getOmega();
356 long phi = round(track.getPhi0() * (1 << precisionPhi));
358 for (
int iSL = 0; iSL < 9; ++iSL) {
359 for (
int priority = 0; priority < 2; ++priority) {
361 m_alpha[iSL][priority] =
362 (m_radius[iSL][priority] * abs(omega) < 2) ?
363 round(asin(m_radius[iSL][priority] * omega / 2) * (1 << precisionAlpha)) :
364 round(M_PI_2 * (1 << precisionAlpha));
365 long dphi = (precisionAlpha >= precisionPhi) ?
366 phi - (
long(m_alpha[iSL][priority]) >> (precisionAlpha - precisionPhi)) :
367 phi - (long(m_alpha[iSL][priority]) << (precisionPhi - precisionAlpha));
368 m_idRef[iSL][priority] =
369 long(dphi * round((m_TSoffset[iSL + 1] - m_TSoffset[iSL]) / 2. / M_PI * (1 << precisionScale)) /
370 (
long(1) << (precisionPhi + precisionScale - precisionId)));
372 m_alpha[iSL][priority] /= (1 << precisionAlpha);
373 m_idRef[iSL][priority] /= (1 << precisionId);
381 int iSL = hit.getISuperLayer();
382 int priority = hit.getPriorityPosition();
384 double relId = hit.getSegmentID() + 0.5 * (((priority >> 1) & 1) - (priority & 1))
385 - m_TSoffset[iSL] - m_idRef[iSL][int(priority < 3)];
386 relId = remainder(relId, (m_TSoffset[iSL + 1] - m_TSoffset[iSL]));
393 if (et_option != m_MLPs[isector].get_et_option()) {
394 B2WARNING(
"Used event time option is different to the one set in the MLP"
395 <<
LogVar(
"et_option", et_option) <<
LogVar(
"isector", isector)
396 <<
LogVar(
"et_option_mlp", m_MLPs[isector].get_et_option()));
398 if (et_option ==
"etf_or_fastestpriority") {
399 bool hasT0 = m_eventTime->hasBinnedEventT0(Const::CDC);
401 m_T0 = m_eventTime->getBinnedEventT0(Const::CDC);
408 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ihit) {
410 if (axialHits.
weight(ihit) < 0)
continue;
411 unsigned short iSL = axialHits[ihit]->getISuperLayer();
413 if ((iSL % 2 == 1) && !neuroinputmode)
continue;
415 double relId = getRelId(*axialHits[ihit]);
416 if (m_MLPs[isector].isRelevant(relId, iSL) &&
417 axialHits[ihit]->priorityTime() < m_T0) {
418 m_T0 = axialHits[ihit]->priorityTime();
421 if (!neuroinputmode) {
424 for (
int ihit = 0; ihit < hits.getEntries(); ++ihit) {
425 unsigned short iSL = hits[ihit]->getISuperLayer();
427 if (iSL % 2 == 0)
continue;
429 double relId = getRelId(*hits[ihit]);
430 if (m_MLPs[isector].isRelevant(relId, iSL) && hits[ihit]->priorityTime() < m_T0) {
431 m_T0 = hits[ihit]->priorityTime();
442 }
else if (et_option ==
"etf_or_fastest2d") {
443 bool hasT0 = m_eventTime->hasBinnedEventT0(Const::CDC);
445 m_T0 = m_eventTime->getBinnedEventT0(Const::CDC);
452 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ihit) {
454 if (axialHits.
weight(ihit) < 0)
continue;
455 unsigned short iSL = axialHits[ihit]->getISuperLayer();
457 if (iSL % 2 == 1)
continue;
459 double relId = getRelId(*axialHits[ihit]);
460 if (m_MLPs[isector].isRelevant(relId, iSL) &&
461 axialHits[ihit]->priorityTime() < m_T0) {
462 m_T0 = axialHits[ihit]->priorityTime();
472 }
else if (et_option ==
"fastestpriority") {
473 B2DEBUG(200,
"et_option is 'fastestpriority'");
478 B2DEBUG(200,
"looping over axials:");
479 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ihit) {
481 if (axialHits.
weight(ihit) < 0)
continue;
482 unsigned short iSL = axialHits[ihit]->getISuperLayer();
484 if ((iSL % 2 == 1) && !neuroinputmode)
continue;
486 B2DEBUG(200,
" check drifttime: SL" + std::to_string(iSL) +
",ID = " + std::to_string(axialHits[ihit]->getSegmentID()) +
", t = " +
487 std::to_string(axialHits[ihit]->priorityTime()));
488 double relId = getRelId(*axialHits[ihit]);
489 if (m_MLPs[isector].isRelevant(relId, iSL) &&
490 axialHits[ihit]->priorityTime() < m_T0) {
491 m_T0 = axialHits[ihit]->priorityTime();
492 B2DEBUG(200,
" new t0: " << std::to_string(m_T0));
495 if (!neuroinputmode) {
498 B2DEBUG(200,
"looping over stereos:");
499 for (
int ihit = 0; ihit < hits.getEntries(); ++ihit) {
500 unsigned short iSL = hits[ihit]->getISuperLayer();
502 if (iSL % 2 == 0)
continue;
504 B2DEBUG(200,
" check drifttime: SL" + std::to_string(iSL) +
",ID = " + std::to_string(hits[ihit]->getSegmentID()) +
", t = " +
505 std::to_string(hits[ihit]->priorityTime()));
506 double relId = getRelId(*hits[ihit]);
507 if (m_MLPs[isector].isRelevant(relId, iSL) && hits[ihit]->priorityTime() < m_T0) {
508 m_T0 = hits[ihit]->priorityTime();
509 B2DEBUG(200,
" new t0: " << std::to_string(m_T0));
520 }
else if (et_option ==
"fastest2d") {
525 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ihit) {
527 if (axialHits.
weight(ihit) < 0)
continue;
528 unsigned short iSL = axialHits[ihit]->getISuperLayer();
530 if (iSL % 2 == 1)
continue;
532 double relId = getRelId(*axialHits[ihit]);
533 if (m_MLPs[isector].isRelevant(relId, iSL) &&
534 axialHits[ihit]->priorityTime() < m_T0) {
535 m_T0 = axialHits[ihit]->priorityTime();
544 }
else if (et_option ==
"zero") {
547 }
else if (et_option ==
"etf_only") {
548 bool hasT0 = m_eventTime->hasBinnedEventT0(Const::CDC);
550 m_T0 = m_eventTime->getBinnedEventT0(Const::CDC);
553 B2ERROR(
"No ETF output, but forced to use ETF!");
557 }
else if (et_option ==
"etf_or_zero") {
558 bool hasT0 = m_eventTime->hasBinnedEventT0(Const::CDC);
560 m_T0 = m_eventTime->getBinnedEventT0(Const::CDC);
567 B2ERROR(
"No valid parameter for et_option (" << et_option <<
" )!");
574 B2WARNING(
"This function is deprecated, it used the flag 'T0fromHits'. "
575 <<
"Give additionally et_option as argument to use the new function. "
576 <<
"et_option is now set for T0fromHits=True to 'etf_fastestpriority' "
577 <<
"and for T0fromHits=false to 'etf_or_zero'.");
578 if (m_MLPs[isector].getT0fromHits()) {
579 getEventTime(isector, track,
"etf_or_fastestpriority");
581 getEventTime(isector, track,
"etf_or_zero");
589 unsigned long driftth = 0;
590 vector<unsigned> nHits;
595 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ ihit) {
597 if (axialHits.
weight(ihit) < 0) {
600 unsigned short iSL = axialHits[ihit]->getISuperLayer();
602 if ((!neurotrackinputmode) && (iSL % 2 == 1))
continue;
604 int t = (m_hasT0) ? axialHits[ihit]->priorityTime() - m_T0 : 0;
605 double relId = getRelId(*axialHits[ihit]);
606 if (t < 0 || t > expert.getTMax()) {
607 if (expert.isRelevant(relId, iSL)) {
608 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
609 driftth |= 1 << (8 - iSL + 9 * nHits[iSL]);
615 if (!neurotrackinputmode) {
617 for (
int ihit = 0; ihit < m_segmentHits.getEntries(); ++ ihit) {
618 unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
620 if (iSL % 2 == 0)
continue;
622 int t = (m_hasT0) ? m_segmentHits[ihit]->priorityTime() - m_T0 : 0;
623 double relId = getRelId(*m_segmentHits[ihit]);
624 if (t < 0 || t > expert.getTMax()) {
625 if (expert.isRelevant(relId, iSL)) {
626 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
627 driftth |= 1 << (8 - iSL + 9 * nHits[iSL]);
639 unsigned long chitPattern = 0;
640 vector<unsigned> nHits;
645 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ ihit) {
647 if (axialHits.
weight(ihit) < 0) {
650 unsigned short iSL = axialHits[ihit]->getISuperLayer();
652 if ((!neurotrackinputmode) && (iSL % 2 == 1))
continue;
653 double relId = getRelId(*axialHits[ihit]);
654 if (expert.isRelevant(relId, iSL)) {
655 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
656 chitPattern |= 1 << (iSL + 9 * nHits[iSL]);
661 if (!neurotrackinputmode) {
663 for (
int ihit = 0; ihit < m_segmentHits.getEntries(); ++ ihit) {
664 unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
666 if (iSL % 2 == 0)
continue;
668 double relId = getRelId(*m_segmentHits[ihit]);
669 if (expert.isRelevant(relId, iSL)) {
670 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
671 chitPattern |= 1 << (iSL + 9 * nHits[iSL]);
684 unsigned long hitPattern = 0;
685 vector<unsigned> nHits;
690 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ ihit) {
692 if (axialHits.
weight(ihit) < 0) {
695 unsigned short iSL = axialHits[ihit]->getISuperLayer();
697 if ((!neurotrackinputmode) && (iSL % 2 == 1))
continue;
699 int t = (m_hasT0) ? axialHits[ihit]->priorityTime() - m_T0 : 0;
702 }
else if (t > expert.getTMax()) {
703 t = expert.getTMax();
705 double relId = getRelId(*axialHits[ihit]);
707 if (expert.isRelevant(relId, iSL)) {
708 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
709 hitPattern |= 1 << (iSL + 9 * nHits[iSL]);
712 B2DEBUG(250,
"hit in SL " << iSL);
714 B2DEBUG(250,
"hit in SL " << iSL <<
" not relevant (relId = " << relId <<
")");
717 if (!neurotrackinputmode) {
719 for (
int ihit = 0; ihit < m_segmentHits.getEntries(); ++ ihit) {
720 unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
722 if (iSL % 2 == 0)
continue;
724 int t = (m_hasT0) ? m_segmentHits[ihit]->priorityTime() - m_T0 : 0;
727 }
else if (t > expert.getTMax()) {
728 t = expert.getTMax();
730 double relId = getRelId(*m_segmentHits[ihit]);
731 if (expert.isRelevant(relId, iSL)) {
732 if (nHits[iSL] < expert.getMaxHitsPerSL()) {
733 hitPattern |= 1 << (iSL + 9 * nHits[iSL]);
736 B2DEBUG(250,
"hit in SL " << iSL);
738 B2DEBUG(250,
"hit in SL " << iSL <<
" not relevant (relId = " << relId <<
")");
742 B2DEBUG(250,
"hitPattern " << hitPattern);
743 return hitPattern & expert.getSLpatternMask();
750 vector<unsigned> selectedHitIds = {};
753 tMin.assign(expert.nNodesLayer(0), expert.getTMax());
754 vector<bool> LRknown;
755 LRknown.assign(expert.nNodesLayer(0),
false);
757 hitIds.assign(expert.nNodesLayer(0), -1);
758 vector<unsigned> nHits;
764 B2DEBUG(250,
"start hit loop over all related hits");
765 for (
unsigned ihit = 0; ihit < allHits.
size(); ++ihit) {
767 if (allHits.
weight(ihit) < 0)
continue;
768 unsigned short iSL = allHits[ihit]->getISuperLayer();
769 if (expert.getSLpatternUnmasked() != 0 &&
770 !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
771 B2DEBUG(250,
"skipping hit in SL " << iSL);
775 int t = (m_hasT0) ? allHits[ihit]->priorityTime() - m_T0 : 0;
778 }
else if (t > expert.getTMax()) {
779 t = expert.getTMax();
781 double relId = getRelId(*allHits[ihit]);
782 if (expert.isRelevant(relId, iSL)) {
784 unsigned short iRef = iSL;
785 if (expert.getMaxHitsPerSL() > 1) {
786 if (nHits[iSL] < expert.getMaxHitsPerSL() &&
787 (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
788 iRef += 9 * nHits[iSL];
792 if ((LRknown[iRef] && !LRknown[
compare]) ||
793 (LRknown[iRef] == LRknown[
compare] && tMin[iRef] < tMin[
compare]))
801 useHit = (allHits[ihit]->LRknown() && t <= tMin[iRef]);
803 useHit = (allHits[ihit]->LRknown() || t <= tMin[iRef]);
805 B2DEBUG(250,
"relevant wire SL " << iSL <<
" LR " << allHits[ihit]->getLeftRight()
806 <<
" t " << t <<
" iRef " << iRef <<
" useHit " << useHit);
809 LRknown[iRef] = allHits[ihit]->LRknown();
811 hitIds[iRef] = allHits[ihit]->getArrayIndex();
816 for (
unsigned iHit = 0; iHit < hitIds.size(); ++iHit) {
817 if (hitIds[iHit] >= 0) selectedHitIds.push_back(hitIds[iHit]);
819 return selectedHitIds;
823 bool returnAllRelevant)
826 vector<unsigned> selectedHitIds = {};
829 tMin.assign(expert.nNodesLayer(0), expert.getTMax());
830 vector<bool> LRknown;
831 LRknown.assign(expert.nNodesLayer(0),
false);
833 hitIds.assign(expert.nNodesLayer(0), -1);
834 vector<unsigned> nHits;
840 B2DEBUG(250,
"start axial hit loop");
841 for (
unsigned ihit = 0; ihit < axialHits.
size(); ++ihit) {
843 if (axialHits.
weight(ihit) < 0)
continue;
844 unsigned short iSL = axialHits[ihit]->getISuperLayer();
846 if (iSL % 2 == 1)
continue;
847 if (expert.getSLpatternUnmasked() != 0 &&
848 !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
849 B2DEBUG(250,
"skipping hit in SL " << iSL);
854 int t = (m_hasT0) ? axialHits[ihit]->priorityTime() - m_T0 : 0;
857 }
else if (t > expert.getTMax()) {
858 t = expert.getTMax();
860 double relId = getRelId(*axialHits[ihit]);
861 if (expert.isRelevant(relId, iSL)) {
863 unsigned short iRef = iSL;
864 if (expert.getMaxHitsPerSL() > 1) {
865 if (nHits[iSL] < expert.getMaxHitsPerSL() &&
866 (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
867 iRef += 9 * nHits[iSL];
871 if ((LRknown[iRef] && !LRknown[
compare]) ||
872 (LRknown[iRef] == LRknown[
compare] && tMin[iRef] < tMin[
compare]))
880 useHit = (axialHits[ihit]->LRknown() && t <= tMin[iRef]);
882 useHit = (axialHits[ihit]->LRknown() || t <= tMin[iRef]);
884 B2DEBUG(250,
"relevant wire SL " << iSL <<
" LR " << axialHits[ihit]->getLeftRight()
885 <<
" t " << t <<
" iRef " << iRef <<
" useHit " << useHit);
888 LRknown[iRef] = axialHits[ihit]->LRknown();
890 hitIds[iRef] = axialHits[ihit]->getArrayIndex();
892 if (returnAllRelevant) selectedHitIds.push_back(axialHits[ihit]->getArrayIndex());
897 B2DEBUG(250,
"start stereo hit loop");
898 for (
int ihit = 0; ihit < m_segmentHits.getEntries(); ++ ihit) {
899 unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
901 if (iSL % 2 == 0)
continue;
902 if (expert.getSLpatternUnmasked() != 0 &&
903 !((expert.getSLpatternUnmasked() >> iSL) & 1)) {
904 B2DEBUG(250,
"skipping hit in SL " << iSL);
908 int t = (m_hasT0) ? m_segmentHits[ihit]->priorityTime() - m_T0 : 0;
911 }
else if (t > expert.getTMax()) {
912 t = expert.getTMax();
914 double relId = getRelId(*m_segmentHits[ihit]);
915 if (expert.isRelevant(relId, iSL)) {
917 unsigned short iRef = iSL;
918 if (expert.getMaxHitsPerSL() > 1) {
919 if (nHits[iSL] < expert.getMaxHitsPerSL() &&
920 (expert.getSLpatternUnmasked() >> (iSL + 9 * nHits[iSL])) & 1) {
921 iRef += 9 * nHits[iSL];
925 if ((LRknown[iRef] && !LRknown[
compare]) ||
926 (LRknown[iRef] == LRknown[
compare] && tMin[iRef] < tMin[
compare]))
934 useHit = (m_segmentHits[ihit]->LRknown() && t <= tMin[iRef]);
936 useHit = (m_segmentHits[ihit]->LRknown() || t <= tMin[iRef]);
938 B2DEBUG(250,
"relevant wire SL " << iSL <<
" LR " << m_segmentHits[ihit]->getLeftRight()
939 <<
" t " << t <<
" iRef " << iRef <<
" useHit " << useHit);
942 LRknown[iRef] = m_segmentHits[ihit]->LRknown();
946 if (returnAllRelevant) selectedHitIds.push_back(ihit);
951 if (!returnAllRelevant) {
952 for (
unsigned iHit = 0; iHit < hitIds.size(); ++iHit) {
953 if (hitIds[iHit] >= 0) selectedHitIds.push_back(hitIds[iHit]);
956 return selectedHitIds;
964 vector<float> inputVector;
965 inputVector.assign(expert.nNodesLayer(0), 0.);
967 vector<unsigned> nHits;
969 for (
unsigned ii = 0; ii < hitIds.size(); ++ii) {
970 int ihit = hitIds[ii];
971 unsigned short iSL = m_segmentHits[ihit]->getISuperLayer();
972 unsigned short iRef = iSL + 9 * nHits[iSL];
974 int t = (m_hasT0) ? m_segmentHits[ihit]->priorityTime() - m_T0 : 0;
977 }
else if (t > expert.getTMax()) {
978 t = expert.getTMax();
980 int LR = m_segmentHits[ihit]->getLeftRight();
981 double relId = getRelId(*m_segmentHits[ihit]);
982 int priority = m_segmentHits[ihit]->getPriorityPosition();
984 inputVector[3 * iRef] = expert.scaleId(relId, iSL);
985 float scaleT = pow(2, floor(log2(1. / expert.getTMax())));
986 inputVector[3 * iRef + 1] = (((LR >> 1) & 1) - (LR & 1)) * t * scaleT;
987 inputVector[3 * iRef + 2] = m_alpha[iSL][int(priority < 3)] * 0.5;
996 vector<float> weights = expert.getWeights();
997 vector<float> layerinput = input;
998 vector<float> layeroutput = {};
1000 for (
unsigned il = 1; il < expert.nLayers(); ++il) {
1002 layerinput.push_back(1.);
1004 layeroutput.clear();
1005 layeroutput.assign(expert.nNodesLayer(il), 0.);
1007 for (
unsigned io = 0; io < layeroutput.size(); ++io) {
1009 for (
unsigned ii = 0; ii < layerinput.size(); ++ii) {
1010 layeroutput[io] += layerinput[ii] * weights[iw++];
1013 layeroutput[io] = tanh(layeroutput[io] / 2.);
1016 layerinput = layeroutput;
1018 return expert.unscaleTarget(layeroutput);
1024 unsigned precisionInput = m_precision[3];
1025 unsigned precisionWeights = m_precision[4];
1026 unsigned precisionLUT = m_precision[5];
1027 unsigned precisionTanh = m_precision[3];
1028 unsigned dp = precisionInput + precisionWeights - precisionLUT;
1032 vector<long> inputFix(input.size(), 0);
1033 for (
unsigned ii = 0; ii < input.size(); ++ii) {
1034 inputFix[ii] = long(input[ii] * (1 << precisionInput));
1037 vector<float> weights = expert.getWeights();
1038 vector<long> weightsFix(weights.size(), 0);
1039 for (
unsigned iw = 0; iw < weights.size(); ++iw) {
1040 weightsFix[iw] = long(round(weights[iw] * (1 << precisionWeights)));
1043 unsigned xMax = unsigned(ceil(atanh(1. - 1. / (1 << (precisionTanh + 1))) *
1044 (1 << (precisionLUT + 1))));
1047 vector<long> layerinput = inputFix;
1048 vector<long> layeroutput = {};
1050 for (
unsigned il = 1; il < expert.nLayers(); ++il) {
1052 layerinput.push_back(1 << precisionInput);
1054 layeroutput.clear();
1055 layeroutput.assign(expert.nNodesLayer(il), 0);
1057 for (
unsigned io = 0; io < layeroutput.size(); ++io) {
1059 for (
unsigned ii = 0; ii < layerinput.size(); ++ii) {
1060 layeroutput[io] += layerinput[ii] * weightsFix[iw++];
1063 unsigned long bin = abs(layeroutput[io]) >> dp;
1065 float x = (bin + 0.5 - 1. / (1 << (dp + 1))) / (1 << precisionLUT);
1066 long tanhLUT = (bin < xMax) ?
long(round(tanh(x / 2.) * (1 << precisionTanh))) : (1 << precisionTanh);
1067 layeroutput[io] = (layeroutput[io] < 0) ? -tanhLUT : tanhLUT;
1070 layerinput = layeroutput;
1074 vector<float> output(layeroutput.size(), 0.);
1075 for (
unsigned io = 0; io < output.size(); ++io) {
1076 output[io] = layeroutput[io] / float(1 << precisionTanh);
1078 return expert.unscaleTarget(output);
1084 B2INFO(
"Saving networks to file " << filename <<
", array " << arrayname);
1085 TFile datafile(filename.c_str(),
"UPDATE");
1086 TObjArray* MLPs =
new TObjArray(m_MLPs.size());
1087 for (
unsigned isector = 0; isector < m_MLPs.size(); ++isector) {
1088 MLPs->Add(&m_MLPs[isector]);
1090 MLPs->Write(arrayname.c_str(), TObject::kSingleKey | TObject::kOverwrite);
1099 if (filename.size() < 1) {
1101 m_MLPs = m_cdctriggerneuroconfig->getMLPs();
1102 if (m_MLPs.size() == 0) {
1103 B2ERROR(
"Could not load Neurotrigger weights from database!");
1106 B2DEBUG(2,
"Loaded Neurotrigger MLP weights from database: " + m_cdctriggerneuroconfig->getNNName());
1107 B2DEBUG(100,
"loaded " << m_MLPs.size() <<
" networks from database");
1112 TFile datafile(filename.c_str(),
"READ");
1113 if (!datafile.IsOpen()) {
1114 B2WARNING(
"Could not open file " << filename);
1118 TObjArray* MLPs = (TObjArray*)datafile.Get(arrayname.c_str());
1121 B2WARNING(
"File " << filename <<
" does not contain key " << arrayname);
1125 for (
int isector = 0; isector < MLPs->GetEntriesFast(); ++isector) {
1127 if (expert) m_MLPs.push_back(*expert);
1128 else B2WARNING(
"Wrong type " << MLPs->At(isector)->ClassName() <<
", ignoring this entry.");
1133 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.
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.
Accessor to arrays stored in the data store.
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.