diff --git a/TrigScint/exampleConfigs/firmwareEx2.py b/TrigScint/exampleConfigs/firmwareEx2.py new file mode 100644 index 000000000..af41393ac --- /dev/null +++ b/TrigScint/exampleConfigs/firmwareEx2.py @@ -0,0 +1,179 @@ +#!/bin/python + +import sys +import os +import json + +# we need the ldmx configuration package to construct the object + +from LDMX.Framework import ldmxcfg + +# set a 'pass name' +passName="sim" +p=ldmxcfg.Process(passName) + +#import all processors +from LDMX.SimCore import generators +from LDMX.SimCore import simulator +from LDMX.Biasing import filters + +from LDMX.Detectors.makePath import * +from LDMX.SimCore import simcfg + +#pull in command line options +nEle=4 # simulated beam electrons +runNum=10 +version="ldmx-det-v14" +outputNameString= "ldmxdetv14gap10mm_firmware.root" #sample identifier +outDir= "" #sample identifier + +# +# Instantiate the simulator. +# +sim = simulator.simulator("test") + +# +# Set the path to the detector to use (pulled from job config) +# +sim.setDetector( version, True ) +sim.scoringPlanes = makeScoringPlanesPath(version) + +outname=outputNameString #+".root" +print("NAME = " + outname) + +# +# Set run parameters. These are all pulled from the job config +# +p.run = runNum +p.maxEvents = 100 +nElectrons = nEle +beamEnergy = 4.0; #in GeV + +sim.description = "Inclusive "+str(beamEnergy)+" GeV electron events, "+str(nElectrons)+"e" +#sim.randomSeeds = [ SEED1 , SEED2 ] +sim.beamSpotSmear = [20., 80., 0] + + +mpgGen = generators.multi( "mgpGen" ) # this is the line that actually creates the generator +mpgGen.vertex = [ -44., 0., -880. ] # mm +mpgGen.nParticles = nElectrons +mpgGen.pdgID = 11 +mpgGen.enablePoisson = False #True + +import math +theta = math.radians(5.45) +beamEnergyMeV=1000*beamEnergy +px = beamEnergyMeV*math.sin(theta) +py = 0.; +pz= beamEnergyMeV*math.cos(theta) +mpgGen.momentum = [ px, py, pz ] + +# +# Set the multiparticle gun as generator +# +sim.generators = [ mpgGen ] + +#reconstruction and vetoes + +#Ecal and Hcal hardwired/geometry stuff +#import LDMX.Ecal.EcalGeometry +import LDMX.Ecal.ecal_hardcoded_conditions +from LDMX.Ecal import EcalGeometry +#egeom = EcalGeometry.EcalGeometryProvider.getInstance() +#Hcal hardwired/geometry stuff +from LDMX.Hcal import HcalGeometry +import LDMX.Hcal.hcal_hardcoded_conditions +#hgeom = HcalGeometry.HcalGeometryProvider.getInstance() + + +from LDMX.Ecal import digi as eDigi +from LDMX.Ecal import vetos +from LDMX.Hcal import digi as hDigi +from LDMX.Hcal import hcal + +from LDMX.Recon.simpleTrigger import TriggerProcessor + +from LDMX.TrigScint.trigScint import TrigScintDigiProducer +from LDMX.TrigScint.trigScint import TrigScintClusterProducer +from LDMX.TrigScint.trigScint import trigScintTrack +from LDMX.TrigScint.trigScint import TrigScintFirmwareTracker + +tsSimColls=[ "TriggerPad2SimHits", "TriggerPad3SimHits", "TriggerPad1SimHits" ] + +# ecal digi chain +# ecalDigi =eDigi.EcalDigiProducer('EcalDigis') +# ecalReco =eDigi.EcalRecProducer('ecalRecon') +# ecalVeto =vetos.EcalVetoProcessor('ecalVetoBDT') + +# #hcal digi chain +# hcalDigi =hDigi.HcalDigiProducer('hcalDigis') +# hcalReco =hDigi.HcalRecProducer('hcalRecon') +# hcalVeto =hcal.HcalVetoProcessor('hcalVeto') +# #hcalDigi.inputCollName="HcalSimHits" +#hcalDigi.inputPassName=passName + +# TS digi + clustering + track chain +tsDigisTag =TrigScintDigiProducer.pad2() +tsDigisTag.input_collection = tsSimColls[0]# +"_"+passName +tsDigisTag.input_pass_name = "sim" +tsDigisUp =TrigScintDigiProducer.pad3() +tsDigisUp.input_collection = tsSimColls[1]# +"_"+passName +tsDigisUp.input_pass_name = "sim" +tsDigisDown=TrigScintDigiProducer.pad1() +tsDigisDown.input_collection = tsSimColls[2]# +"_"+passName +tsDigisDown.input_pass_name = "sim" + +tsClustersTag =TrigScintClusterProducer.pad2() +tsClustersUp =TrigScintClusterProducer.pad1() +tsClustersDown =TrigScintClusterProducer.pad3() + + +tsDigisUp.verbosity=0 +tsClustersUp.verbosity=1 +trigScintTrack.verbosity=1 + +trigScintTrack.delta_max = 0.75 + +trigFirm = TrigScintFirmwareTracker( "trigFirm" ) +trigFirm.input_pass_name = "sim" +trigFirm.digis1_collection = "trigScintDigisPad1" +trigFirm.digis2_collection = "trigScintDigisPad2" +trigFirm.digis3_collection = "trigScintDigisPad3" +trigFirm.output_collection = "TriggerPadTracksFirmware" + +from LDMX.Recon.electronCounter import ElectronCounter +eCount = ElectronCounter( nElectrons, "ElectronCounter") # first argument is number of electrons in simulation +eCount.use_simulated_electron_number = False +eCount.input_collection="TriggerPadTracks" +eCount.input_pass_name=passName + +from LDMX.TrigScint.trigScint import TrigScintFirmwareHitProducer +from LDMX.TrigScint.trigScint import TrigScintQIEDigiProducer +from LDMX.TrigScint.trigScint import TrigScintRecHitProducer + +qieDigi = TrigScintQIEDigiProducer.pad3() +rechit = TrigScintRecHitProducer.pad3() +hitFirm = TrigScintFirmwareHitProducer( "hitFirm" ) +hitFirm.verbose = True + + + +# # p.sequence=[ sim, ecalDigi, ecalReco, ecalVeto, hcalDigi, hcalReco, hcalVeto, tsDigisTag, tsDigisUp, tsDigisDown, tsClustersTag, tsClustersUp, tsClustersDown, trigScintTrack, eCount ] +# #hcal digi keeps crashing in config step +p.sequence=[ sim, tsDigisTag, tsDigisUp, tsDigisDown, tsClustersTag, tsClustersUp, tsClustersDown, trigScintTrack, trigFirm, eCount, qieDigi, rechit, hitFirm] +# p.sequence=[sim] + +p.outputFiles=[outname] + +p.termLogLevel = 0 # default is 2 (WARNING); but then logFrequency is ignored. level 1 = INFO. + +#print this many events to stdout (independent on number of events, edge case: round-off effects when not divisible. so can go up by a factor 2 or so) +logEvents=20 +if p.maxEvents < logEvents : + logEvents = p.maxEvents +p.logFrequency = int( p.maxEvents/logEvents ) + +json.dumps(p.parameterDump(), indent=2) + +with open('parameterDump.json', 'w') as outfile: + json.dump(p.parameterDump(), outfile, indent=4) diff --git a/TrigScint/include/TrigScint/Firmware/hitproducer.h b/TrigScint/include/TrigScint/Firmware/hitproducer.h new file mode 100644 index 000000000..fad178164 --- /dev/null +++ b/TrigScint/include/TrigScint/Firmware/hitproducer.h @@ -0,0 +1,15 @@ +#ifndef HITPRODUCER_H +#define HITPRODUCER_H + +#include "objdef.h" + +#ifdef TS_NOT_EMULATION +void copyHit1(Hit One, Hit Two); +void copyHit2(Hit One, Hit Two); +void hitproducer_ref(ap_uint<14> FIFO[NHITS][5], Hit outHit[NHITS], + ap_uint<8> Peds[NHITS]); +#endif +void hitproducer_hw(ap_uint<14> FIFO[NHITS][5], Hit outHit[NHITS], + ap_uint<8> Peds[NHITS]); + +#endif diff --git a/TrigScint/include/TrigScint/Firmware/objdef.h b/TrigScint/include/TrigScint/Firmware/objdef.h index 09bb76075..bbf0086e5 100644 --- a/TrigScint/include/TrigScint/Firmware/objdef.h +++ b/TrigScint/include/TrigScint/Firmware/objdef.h @@ -2,7 +2,7 @@ #define OBJDEF_H #include "ap_int.h" -#define NTIMES 6 +#define NTIMES 5 #define NHITS 25 #define NCLUS 25 #define NCHAN 50 diff --git a/TrigScint/include/TrigScint/TrigScintFirmwareHitProducer.h b/TrigScint/include/TrigScint/TrigScintFirmwareHitProducer.h new file mode 100644 index 000000000..60597a2bf --- /dev/null +++ b/TrigScint/include/TrigScint/TrigScintFirmwareHitProducer.h @@ -0,0 +1,88 @@ +/** + * @file TrigScintFirmwareHitProducer.h + * @brief Staging of Real Hits + * @author Lene Kristian Bryngemark, Stanford University + */ + +#ifndef TRIGSCINT_TRIGSCINTFIRMWAREHITPRODUCER_H +#define TRIGSCINT_TRIGSCINTFIRMWAREHITPRODUCER_H + +/*~~~~~~~~~~*/ +/* ROOT */ +/*~~~~~~~~~~*/ +#include "TRandom3.h" + +// LDMX +#include "DetDescr/TrigScintID.h" +#include "Recon/Event/EventConstants.h" +#include "Tools/NoiseGenerator.h" +#include "TrigScint/Event/TrigScintHit.h" +#include "TrigScint/Event/TrigScintQIEDigis.h" + +/*~~~~~~~~~~~~~~~*/ +/* Framework */ +/*~~~~~~~~~~~~~~~*/ +#include "Framework/Configure/Parameters.h" +#include "Framework/EventProcessor.h" + +/*~~~~~~~~~~~*/ +/* TrigScint */ +/*~~~~~~~~~~~*/ +#include "TrigScint/Firmware/objdef.h" +#include "TrigScint/SimQIE.h" + +namespace trigscint { + +/** + * @class TrigScintFirmwareHitProducer + * @brief + */ +class TrigScintFirmwareHitProducer : public framework::Producer { + public: + TrigScintFirmwareHitProducer(const std::string& name, + framework::Process& process) + : Producer(name, process) {} + + void configure(framework::config::Parameters& ps) override; + + void produce(framework::Event& event) override; + + /** + * add a hit at index idx to a cluster + */ + + private: + /// Name of the input collection containing the sim hits + std::string inputCollection_; + + /// Name of the pass that the input collection is on (empty string means take + /// any pass) + std::string inputPassName_; + + /// Name of the output collection that will be used to stored the + /// digitized trigger scintillator hits + std::string outputCollection_; + + /// SiPM gain + double gain_{1e6}; + + /// QIE pedestal + double pedestal_{6.0}; + + /// Total MeV per MIP + double mevPerMip_{1.40}; + + /// Total number of photoelectrons per MIP + double pePerMip_{13.5}; + + /// Total number of photoelectrons per MIP + int sample_of_interest_{2}; + + std::string testCollection_; + + bool doTest_{true}; +}; + +} // namespace trigscint + +#endif /* TRIGSCINT_TRIGSCINTFIRMWAREHITPRODUCER_H */ diff --git a/TrigScint/python/trigScint.py b/TrigScint/python/trigScint.py index f8fcbec77..78dd22cd7 100644 --- a/TrigScint/python/trigScint.py +++ b/TrigScint/python/trigScint.py @@ -219,6 +219,48 @@ def pad3() : rechit.output_collection = 'trigScintRecHitsPad3' return rechit +class TrigScintFirmwareHitProducer(ldmxcfg.Producer) : + """Configuration for rechit producer for Trigger Scintillators incorporating validated Firmware, regular and pileUp""" + + def __init__(self,name) : + super().__init__(name,'trigscint::TrigScintFirmwareHitProducer','TrigScint') + + self .mev_per_mip = 0.4 #\ + # >>>both are for converting edep to PEs + self.pe_per_mip = 100. #/ + self.pedestal= 6.0 # QIE pedestal value (in fC) + self.gain = 1.e6 # SiPM Gain + self.input_collection="trigScintQIEDigisPad3" + self.test_collection="trigScintRecHitsPad3" + self.input_pass_name="" #take any pass + self.output_collection="trigScintFirmHitsPad3" + self.verbose = False + self.sample_of_interest=2 # Sample of interest. Range 0 to 3 + + def pad1() : + """Get the firmware hit producer for first pad""" + rechit = TrigScintRecHitProducer( 'trigScintFirmHitsPad1' ) + rechit.input_collection = 'trigScintQIEDigisPad1' + rechit.output_collection = 'trigScintFirmHitsPad1' + rechit.test_collection = 'trigScintRecHitsPad1' + return rechit + + def pad2() : + """Get the firmware hit producer for second pad""" + rechit = TrigScintRecHitProducer( 'trigScintFirmHitsPad2' ) + rechit.input_collection = 'trigScintQIEDigisPad2' + rechit.output_collection = 'trigScintFirmHitsPad2' + rechit.test_collection = 'trigScintRecHitsPad2' + return rechit + + def pad3() : + """Get the firmware hit for third pad""" + rechit = TrigScintRecHitProducer( 'trigScintFirmHitsPad3' ) + rechit.input_collection = 'trigScintQIEDigisPad3' + rechit.output_collection = 'trigScintFirmHitsPad3' + rechit.test_collection= 'trigScintRecHitsPad3' + return rechit + class TrigScintClusterProducer(ldmxcfg.Producer) : """Configuration for cluster producer for Trigger Scintillators""" diff --git a/TrigScint/src/TrigScint/Firmware/hitproducer_hw.cxx b/TrigScint/src/TrigScint/Firmware/hitproducer_hw.cxx new file mode 100644 index 000000000..f9b2e43f9 --- /dev/null +++ b/TrigScint/src/TrigScint/Firmware/hitproducer_hw.cxx @@ -0,0 +1,169 @@ +#include + +#include + +#include "TrigScint/Firmware/hitproducer.h" +#include "TrigScint/Firmware/objdef.h" + +void hitproducer_hw(ap_uint<14> FIFO[NHITS][5], Hit outHit[NHITS], + ap_uint<8> Peds[NHITS]) { +#ifdef TS_NOT_EMULATION +#pragma HLS ARRAY_PARTITION variable = FIFO complete +#pragma HLS ARRAY_PARTITION variable = amplitude complete +#pragma HLS ARRAY_PARTITION variable = Peds complete +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[0] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[1] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[2] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[3] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[4] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[5] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[6] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[7] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[8] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[9] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[10] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[11] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[12] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[13] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[14] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[15] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[16] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[17] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[18] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[19] + +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[20] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[21] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[22] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[23] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[24] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[25] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[26] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[27] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[28] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[29] + +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[30] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[31] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[32] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[33] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[34] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[35] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[36] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[37] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[38] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[39] + +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[40] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[41] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[42] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[43] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[44] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[45] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[46] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[47] + +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[48] +#pragma HLS INTERFACE ap_fifo depth = 16 port = FIFO[49] + +#pragma HLS PIPELINE +#endif + + // The QIE11 card takes an analogue SiPM PE count + // and converts electron counts from it via a piecewise + // exponential curve into an ADC. Depending on the shunts + // you use, you can affect the gain; the gains and variable + // values determined here are motived primarily by those required + // to get the MIP distribution seen in the 2022 beam. + // The next variables show where each linear portion of the + // exponential map start in charge count (edges_) and their slope; + // the hitmaker delinearized the adc counts, integrates over five clockcycles + // and forms a hit. + + /// Indices of first bin of each subrange + ap_uint<14> nbins_[5] = {0, 16, 36, 57, 64}; + + /// Charge lower limit of all the 16 subranges + ap_uint<14> edges_[17] = {0, 34, 158, 419, 517, 915, + 1910, 3990, 4780, 7960, 15900, 32600, + 38900, 64300, 128000, 261000, 350000}; + /// sensitivity of the subranges (Total charge/no. of bins) + ap_uint<14> sense_[16] = {3, 6, 12, 25, 25, 50, 99, 198, + 198, 397, 794, 1587, 1587, 3174, 6349, 12700}; + + for (int i = 0; i < NHITS; i++) { + outHit[i].bID = -1; + outHit[i].mID = 0; + outHit[i].Time = 0; + outHit[i].Amp = 0; + ap_uint<14> word1 = FIFO[i][0]; + ap_uint<14> word2 = FIFO[i][1]; + ap_uint<14> word3 = FIFO[i][2]; + ap_uint<14> word4 = FIFO[i][3]; + ap_uint<14> word5 = FIFO[i][4]; + ap_uint<16> charge1; + ap_uint<16> charge2; + ap_uint<16> charge3; + ap_uint<16> charge4; + ap_uint<16> charge5; + ap_uint<4> shunt = 1; + // An identical procedure is used for all 5 clockcylces. Namely you extract + // the adc value from the adc+tdc concatenated value you get from the raw + // strwam via (word1>>6); You then use what integer multiple of 64 it is to + // determine which linear segment you are on, and v1 (the remainder) to + // determine how far along that linear segment your charge carried you. + // Together that gets you charge. + + ap_uint<14> rr = (word1 >> 6) / 64; + ap_uint<14> v1 = (word1 >> 6) % 64; + ap_uint<14> ss = + 1 * (v1 > nbins_[1]) + 1 * (v1 > nbins_[2]) + 1 * (v1 > nbins_[3]); + charge1 = edges_[4 * rr + ss] + (v1 - nbins_[ss]) * sense_[4 * rr + ss] + + sense_[4 * rr + ss] / 2 - 1; + + rr = (word2 >> 6) / 64; + v1 = (word2 >> 6) % 64; + ss = 1 * (v1 > nbins_[1]) + 1 * (v1 > nbins_[2]) + 1 * (v1 > nbins_[3]); + charge2 = edges_[4 * rr + ss] + (v1 - nbins_[ss]) * sense_[4 * rr + ss] + + sense_[4 * rr + ss] / 2 - 1; + + rr = (word3 >> 6) / 64; + v1 = (word3 >> 6) % 64; + ss = 1 * (v1 > nbins_[1]) + 1 * (v1 > nbins_[2]) + 1 * (v1 > nbins_[3]); + charge3 = edges_[4 * rr + ss] + (v1 - nbins_[ss]) * sense_[4 * rr + ss] + + sense_[4 * rr + ss] / 2 - 1; + + rr = (word4 >> 6) / 64; + v1 = (word4 >> 6) % 64; + ss = 1 * (v1 > nbins_[1]) + 1 * (v1 > nbins_[2]) + 1 * (v1 > nbins_[3]); + charge4 = edges_[4 * rr + ss] + (v1 - nbins_[ss]) * sense_[4 * rr + ss] + + sense_[4 * rr + ss] / 2 - 1; + + rr = (word5 >> 6) / 64; + v1 = (word5 >> 6) % 64; + ss = 1 * (v1 > nbins_[1]) + 1 * (v1 > nbins_[2]) + 1 * (v1 > nbins_[3]); + charge5 = edges_[4 * rr + ss] + (v1 - nbins_[ss]) * sense_[4 * rr + ss] + + sense_[4 * rr + ss] / 2 - 1; + + outHit[i].bID = i; + + // You now are creating an output hit. The time of the hit is determined by + // the last part of the concatenated streamed tdc, which is 6 bits and + // therefore you mask the word1 with 63 (which is 111111 in binary) so as + // only to keep the tdc. + + outHit[i].Time = (word1 & 63); + + // The 36 remaining here is an artefact of the mapping that the charges have + // to adcs; its not particularly meaningful except that it establishes that + // 0 adc corresponds to 0 charge. The .00625 value is a value which is + // conglomerate but relates to the number of PE's produced; it will change + // based on the number of shunts employed during a run. + + outHit[i].Amp = + shunt * + ((charge1 + charge2 + charge3 + charge4 + charge5 - 36) * .00625); + } + + return; +} diff --git a/TrigScint/src/TrigScint/TrigScintFirmwareHitProducer.cxx b/TrigScint/src/TrigScint/TrigScintFirmwareHitProducer.cxx new file mode 100644 index 000000000..a7eb902e2 --- /dev/null +++ b/TrigScint/src/TrigScint/TrigScintFirmwareHitProducer.cxx @@ -0,0 +1,87 @@ + +#include "TrigScint/TrigScintFirmwareHitProducer.h" + +#include +#include + +#include "TrigScint/Firmware/hitproducer.h" +#include "TrigScint/Firmware/objdef.h" + +namespace trigscint { + +void TrigScintFirmwareHitProducer::configure( + framework::config::Parameters &ps) { + pedestal_ = ps.getParameter("pedestal"); + gain_ = ps.getParameter("gain"); + mevPerMip_ = ps.getParameter("mev_per_mip"); + pePerMip_ = ps.getParameter("pe_per_mip"); + inputCollection_ = ps.getParameter("input_collection"); + testCollection_ = ps.getParameter("test_collection"); + inputPassName_ = ps.getParameter("input_pass_name"); + outputCollection_ = ps.getParameter("output_collection"); + sample_of_interest_ = ps.getParameter("sample_of_interest"); + ldmx_log(debug) << "In TrigScintFirmwareHitProducer: configure done!"; + ldmx_log(debug) << "\nPedestal: " << pedestal_ << "\nGain: " << gain_ + << "\nMEV per MIP: " << mevPerMip_ + << "\nPE per MIP: " << pePerMip_ + << "\ninput collection: " << inputCollection_ + << "\ntest collection: " << testCollection_ + << "\nAre we testing: " << doTest_ + << "\nInput pass name: " << inputPassName_ + << "\nOutput collection: " << outputCollection_; + return; +} + +void TrigScintFirmwareHitProducer::produce(framework::Event &event) { + // This processor takes in TS QIE digis and outputs a rec hit collection. It + // does so using hitproducer_hw, which is a validated piece of HLS code whose + // purpose is to emulate existing reconstruction software in firmware for + // triggering. I will more fully explain the operation and choices made in + // hitproducer_hw in hitproducer_hw + const auto rechits{ + event.getCollection(testCollection_, inputPassName_)}; + for (const auto &hit : rechits) { + ldmx_log(debug) << "Analysis barID: " << hit.getBarID() + << ", PE Number: " << hit.getPE(); + } + const auto digis{event.getCollection( + inputCollection_, inputPassName_)}; + Hit outHit[NHITS]; + ap_uint<14> FIFO[NCHAN][NTIMES]; + ap_uint<8> Peds[NCHAN]; + for (int i = 0; i < NCHAN; i++) { + Peds[i] = 0; + FIFO[i][0] = (Peds[i] << 6) + 63; + FIFO[i][1] = (Peds[i] << 6) + 63; + FIFO[i][2] = (Peds[i] << 6) + 63; + FIFO[i][3] = (Peds[i] << 6) + 63; + FIFO[i][4] = (Peds[i] << 6) + 63; + } + for (const auto &digi : digis) { + std::vector adcs = digi.getADC(); + std::vector tdcs = digi.getTDC(); + for (int i = 0; i < NTIMES; i++) { + FIFO[digi.getChanID()][i] = (ap_uint<14>)((adcs[i] << 6) + (tdcs[i])); + } + } + hitproducer_hw(FIFO, outHit, Peds); + std::vector trigScintHits; + for (int i = 0; i < NHITS; i++) { + if (outHit[i].Amp >= 3) { + ldmx_log(debug) << "Firmware barID: " << outHit[i].bID + << ", PE Number: " << outHit[i].Amp; + ldmx::TrigScintHit hit; + hit.setModuleID(outHit[i].mID); + hit.setBarID(outHit[i].bID); + hit.setTime(outHit[i].Time); + hit.setPE(outHit[i].Amp); + trigScintHits.push_back(hit); + } + } + event.add(outputCollection_, trigScintHits); + return; +} + +} // namespace trigscint + +DECLARE_PRODUCER_NS(trigscint, TrigScintFirmwareHitProducer); diff --git a/TrigScint/src/TrigScint/TrigScintFirmwareTracker.cxx b/TrigScint/src/TrigScint/TrigScintFirmwareTracker.cxx index ee14975f6..04916b68d 100644 --- a/TrigScint/src/TrigScint/TrigScintFirmwareTracker.cxx +++ b/TrigScint/src/TrigScint/TrigScintFirmwareTracker.cxx @@ -62,7 +62,7 @@ void TrigScintFirmwareTracker::produce(framework::Event &event) { for (int i = 0; i < NCENT; ++i) { for (int j = 0; j < COMBO; ++j) { for (int k = 0; k < 2; ++k) { - LOOKUP[i][j][k] = ap_int<12>(0); + LOOKUP[i][j][k] = ap_int<12>(-1); } } } @@ -278,9 +278,9 @@ void TrigScintFirmwareTracker::produce(framework::Event &event) { // clusters in Pad1. Do not change this. trackproducer_hw(Pad1, Pad2, Pad3, outTrk, LOOKUP); for (int I = 0; I < NTRK; I++) { - if (outTrk[I].Pad1.Seed.Amp > 0. && outTrk[I].Pad1.Sec.Amp > 0. && - outTrk[I].Pad2.Seed.Amp > 0. && outTrk[I].Pad2.Sec.Amp > 0. && - outTrk[I].Pad3.Seed.Amp > 0. && outTrk[I].Pad3.Sec.Amp > 0.) { + if (outTrk[I].Pad1.Seed.Amp > 0. && outTrk[I].Pad1.Sec.Amp >= 0. && + outTrk[I].Pad2.Seed.Amp > 0. && outTrk[I].Pad2.Sec.Amp >= 0. && + outTrk[I].Pad3.Seed.Amp > 0. && outTrk[I].Pad3.Sec.Amp >= 0.) { ldmx::TrigScintTrack trk = makeTrack(outTrk[I]); tracks_.push_back(trk); }