LDMX Software
trigscint::QIEDecoder Class Reference

Public Member Functions

 QIEDecoder (const std::string &name, framework::Process &process)
 
virtual ~QIEDecoder ()=default
 Default destructor, closes up boost archive and input stream.
 
void configure (framework::config::Parameters &ps) override
 Configure our converter based off the configuration parameters decoded from the passed python script.
 
void produce (framework::Event &event) override
 Process the event and put new data products into it.
 
void onProcessStart () override
 Callback for the EventProcessor to take any necessary action when the processing of events starts, such as creating histograms.
 
void onProcessEnd () override
 Callback for the EventProcessor to take any necessary action when the processing of events finishes, such as calculating job-summary quantities.
 
- Public Member Functions inherited from framework::Producer
 Producer (const std::string &name, Process &process)
 Class constructor.
 
virtual void process (Event &event) final
 Processing an event for a Producer is calling produce.
 
- Public Member Functions inherited from framework::EventProcessor
 DECLARE_FACTORY (EventProcessor, EventProcessor *, const std::string &, Process &)
 declare that we have a factory for this class
 
 EventProcessor (const std::string &name, Process &process)
 Class constructor.
 
virtual ~EventProcessor ()=default
 Class destructor.
 
virtual void beforeNewRun (ldmx::RunHeader &run_header)
 Callback for Producers to add parameters to the run header before conditions are initialized.
 
virtual void onNewRun (const ldmx::RunHeader &run_header)
 Callback for the EventProcessor to take any necessary action when the run being processed changes.
 
virtual void onFileOpen (EventFile &event_file)
 Callback for the EventProcessor to take any necessary action when a new event input ROOT file is opened.
 
virtual void onFileClose (EventFile &event_file)
 Callback for the EventProcessor to take any necessary action when a event input ROOT file is closed.
 
template<class T >
const T & getCondition (const std::string &condition_name)
 Access a conditions object for the current event.
 
TDirectory * getHistoDirectory ()
 Access/create a directory in the histogram file for this event processor to create histograms and analysis tuples.
 
void setStorageHint (framework::StorageControl::Hint hint)
 Mark the current event as having the given storage control hint from this module_.
 
void setStorageHint (framework::StorageControl::Hint hint, const std::string &purposeString)
 Mark the current event as having the given storage control hint from this module and the given purpose string.
 
int getLogFrequency () const
 Get the current logging frequency from the process.
 
int getRunNumber () const
 Get the run number from the process.
 
std::string getName () const
 Get the processor name.
 
void createHistograms (const std::vector< framework::config::Parameters > &histos)
 Internal function which is used to create histograms passed from the python configuration @parma histos vector of Parameters that configure histograms to create.
 

Private Attributes

std::string channel_map_file_name_
 the channel mapping
 
std::ifstream channel_map_file_
 
std::map< int, int > channel_map_
 
std::string input_collection_
 
std::string output_collection_
 
std::string input_pass_name_
 
int n_channels_ {50}
 
int n_samples_ {5}
 
bool is_real_data_ {false}
 

Additional Inherited Members

- Protected Member Functions inherited from framework::EventProcessor
void abortEvent ()
 Abort the event immediately.
 
- Protected Attributes inherited from framework::EventProcessor
HistogramPool histograms_
 helper object for making and filling histograms
 
NtupleManager & ntuple_ {NtupleManager::getInstance()}
 Manager for any ntuples.
 
logging::logger the_log_
 The logger for this EventProcessor.
 

Detailed Description

Definition at line 11 of file QIEDecoder.h.

Constructor & Destructor Documentation

◆ QIEDecoder()

trigscint::QIEDecoder::QIEDecoder ( const std::string & name,
framework::Process & process )
inline

Definition at line 13 of file QIEDecoder.h.

14 : Producer(name, process) {}
Producer(const std::string &name, Process &process)
Class constructor.
virtual void process(Event &event) final
Processing an event for a Producer is calling produce.

Member Function Documentation

◆ configure()

void trigscint::QIEDecoder::configure ( framework::config::Parameters & ps)
overridevirtual

Configure our converter based off the configuration parameters decoded from the passed python script.

Reimplemented from framework::EventProcessor.

Definition at line 14 of file QIEDecoder.cxx.

14 {
15 // Configure this instance of the encoder
16 output_collection_ = ps.get<std::string>("output_collection");
17 input_collection_ = ps.get<std::string>("input_collection");
18 input_pass_name_ = ps.get<std::string>("input_pass_name");
19 channel_map_file_name_ = ps.get<std::string>("channel_map_file");
20 n_channels_ = ps.get<int>("number_channels");
21 n_samples_ = ps.get<int>("number_time_samples");
22 is_real_data_ = ps.get<bool>("is_real_data");
23
24 ldmx_log(debug) << "In configure, got parameters:" << "\noutput_collection = "
25 << output_collection_
26 << "\ninput_collection = " << input_collection_
27 << "\ninput_pass_name = " << input_pass_name_
28 << "\nchannel_map_file = " << channel_map_file_name_
29 << "\nnumber_channels = " << n_channels_
30 << "\nnumber_time_samples = " << n_samples_
31 << "\nis_real_data = " << is_real_data_;
32
33 channel_map_file_.open(channel_map_file_name_, std::ios::in);
34 if (!channel_map_file_.is_open()) {
35 EXCEPTION_RAISE(
36 "BadMapFile",
37 "The channel mapping file cannot be opened."); // <-- appears this
38 // needs implementing
39 // first
40 ldmx_log(fatal) << "The channel mapping file cannot be opened.";
41 return;
42 }
43 int ch_id, el_id;
44 while (!channel_map_file_.eof()) {
45 channel_map_file_ >> el_id >> ch_id;
46 // make the map based on electronics ID, to look up channel ID.
47 // the reason is, we will only know the elecID from the position
48 // of the word in the stream. so these need to be strictly ordered.
49 // writing the right bar in the right position is easier if we can just
50 // read this map from beginning to end.
51 // barID can always be set, or looked up, as a property of the digi.
52
53 // here make the elecID the key (other way around when encoding)
54 channel_map_.insert(std::pair<int, int>(el_id, ch_id));
55 ldmx_log(debug) << el_id << " chID " << ch_id;
56 }
57 channel_map_file_.close();
58 if (el_id != n_channels_ - 1)
59 ldmx_log(fatal) << "The set number of channels " << n_channels_
60 << " seems not to match the number from the map (+1) :"
61 << el_id;
62 return;
63}
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:75
std::string channel_map_file_name_
the channel mapping
Definition QIEDecoder.h:35

References channel_map_file_name_, and framework::config::Parameters::get().

◆ onProcessEnd()

void trigscint::QIEDecoder::onProcessEnd ( )
overridevirtual

Callback for the EventProcessor to take any necessary action when the processing of events finishes, such as calculating job-summary quantities.

Reimplemented from framework::EventProcessor.

Definition at line 302 of file QIEDecoder.cxx.

302 {
303 ldmx_log(debug) << "Process ends!";
304
305 return;
306}

◆ onProcessStart()

void trigscint::QIEDecoder::onProcessStart ( )
overridevirtual

Callback for the EventProcessor to take any necessary action when the processing of events starts, such as creating histograms.

Reimplemented from framework::EventProcessor.

Definition at line 296 of file QIEDecoder.cxx.

296 {
297 ldmx_log(debug) << "Process starts!";
298
299 return;
300}

◆ produce()

void trigscint::QIEDecoder::produce ( framework::Event & event)
overridevirtual

Process the event and put new data products into it.

Parameters
eventThe Event to process.

Implements framework::Producer.

Definition at line 65 of file QIEDecoder.cxx.

65 {
66 ldmx_log(debug) << "QIEDecoder: produce() starts! Event number: "
67 << event.getEventHeader().getEventNumber();
68
69 // turns out this need to be configurable for now, to read real data
70 int n_samp = n_samples_; // QIEStream::NUM_SAMPLES ;
71 ldmx_log(debug) << "num samples = " << n_samp;
72
73 ldmx_log(debug) << "Looking up input collection " << input_collection_ << "_"
74 << input_pass_name_;
75 const auto event_stream{
76 event.getCollection<uint8_t>(input_collection_, input_pass_name_)};
77 ldmx_log(debug) << "Got input collection" << input_collection_ << "_"
78 << input_pass_name_;
79
80 uint32_t time_epoch = 0;
81 // these don't have to be in any particular order, position is anyway looked
82 // up from definition in header
83 for (int i_w = 0; i_w < QIEStream::TIMESTAMP_LEN_BYTES; i_w++) {
84 int pos = QIEStream::TIMESTAMP_POS + i_w;
85 uint8_t time_word = event_stream.at(pos);
86 ldmx_log(debug) << "time stamp word at position " << pos
87 << " (with iW = " << i_w
88 << ") = " << std::bitset<8>(time_word);
89 time_epoch |= (time_word << i_w * 8); // shift by a byte at a time
90 }
91
92 uint32_t time_clock = 0;
93 for (int i_w = 0; i_w < QIEStream::TIMESTAMPCLOCK_LEN_BYTES; i_w++) {
94 int pos = QIEStream::TIMESTAMPCLOCK_POS + i_w;
95 uint8_t time_word = event_stream.at(pos);
96 ldmx_log(debug) << "time stamp ns word at position " << pos
97 << " (with iW = " << i_w
98 << ") = " << std::bitset<8>(time_word);
99 time_clock |= (time_word << i_w * 8); // shift by a byte at a time
100 }
101
102 uint32_t time_spill = 0;
103 ldmx_log(debug) << "Before starting, timeSpill = " << time_spill << " ("
104 << std::bitset<64>(time_spill) << ", or, " << std::hex
105 << time_spill << std::dec << ") counts since start of spill";
106
107 for (int i_w = 0; i_w < QIEStream::TIMESINCESPILL_LEN_BYTES; i_w++) {
108 int pos = QIEStream::TIMESINCESPILL_POS + i_w;
109 uint8_t time_word = event_stream.at(pos);
110 ldmx_log(debug) << "time since spill word at position " << pos
111 << " (with iW = " << i_w
112 << ") = " << std::bitset<8>(time_word);
113 time_spill |= (time_word << i_w * 8); // shift by a byte at a time
114 }
115 ldmx_log(debug) << "time stamp words are : " << time_epoch << " ("
116 << std::bitset<64>(time_epoch) << ") and " << time_clock
117 << " (" << std::bitset<64>(time_clock)
118 << ") clock ticks, and " << time_spill << " ("
119 << std::bitset<64>(time_spill) << ", or, " << std::hex
120 << time_spill << std::dec << ") counts since start of spill";
121
122 int sig_bits_skip = 6; // the first 6 bits are part of something else.
123 int divisor = TMath::Power(2, 32 - sig_bits_skip);
124 // remove them by taking remainder in division by
125 // the values of the last skipped bit
126 time_spill = time_spill % divisor;
127 ldmx_log(debug) << "After taking it mod 2^" << 32 - sig_bits_skip
128 << " (which is " << divisor << ", spill time is "
129 << time_spill;
130 event.getEventHeader().setIntParameter("timeSinceSpill", time_spill);
131
132 TTimeStamp* time_stamp = new TTimeStamp(time_epoch);
133 event.getEventHeader().setTimestamp(*time_stamp);
134
135 // trigger ID event number
136 uint32_t trigger_id = 0;
137
138 for (int i_w = 0; i_w < QIEStream::TRIGID_LEN_BYTES; i_w++) {
139 // assume the whole 3B are written as a single 24 bits word
140 int pos = QIEStream::TRIGID_POS + i_w;
141 uint8_t t_i_dword = event_stream.at(pos);
142 ldmx_log(debug) << "trigger word at position " << pos
143 << " (with iW = " << i_w
144 << ") = " << std::bitset<8>(t_i_dword);
145 trigger_id |= (t_i_dword << i_w * 8); // shift by a byte at a time
146 }
147
148 // ldmx_log(debug) << " got triggerID " << std::bitset<16>(triggerID) ;
149 ldmx_log(debug) << " got triggerID " << std::bitset<32>(trigger_id);
150
151 if (trigger_id != event.getEventHeader().getEventNumber()) {
152 // this probably only applies to digi emulation,
153 // unless an event number is explicitly set in unpacking
154 ldmx_log(fatal) << "Got event number mismatch: framework reports "
155 << event.getEventHeader().getEventNumber()
156 << ", stream says " << trigger_id;
157 }
158
159 // error word
160 /* the error word contains
161 - 4 trailing reserved 0's, for now
162 - isCIDunsync : if there is a mismatch between CID reported by channels
163 within the same time sample
164 - isCIDskipped : if there is a gap in the CID increment of a channel
165 beweeen samples
166 - isCRC0malformed : if there was an issue with CRC from fiber0
167 - isCRC1malformed : if there was an issue with CRC from fiber1
168 */
169 uint8_t flags = event_stream.at(QIEStream::ERROR_POS);
170
171 bool is_ci_dskipped{static_cast<bool>((flags >> QIEStream::CID_SKIP_POS) &
173 bool is_ci_dunsync{static_cast<bool>((flags >> QIEStream::CID_UNSYNC_POS) &
175 // These are unused, should they be? FIXME
176 // bool isCRC1malformed{static_cast<bool>((flags >> QIEStream::CRC1_ERR_POS) &
177 // Mask8<QIEStream::FLAG_SIZE_BITS>::m)};
178 // bool isCRC0malformed{static_cast<bool>((flags >> QIEStream::CRC0_ERR_POS) &
179 // Mask8<QIEStream::FLAG_SIZE_BITS>::m)};
180
181 // checksum
182 // really, this is just empty for now.
183 // TODO: implement a checksum set/get
184 uint8_t reference_checksum = 0;
185 int checksum{(flags >> QIEStream::CHECKSUM_POS) &
187 // eventStream.at(QIEStream::CRC0_ERR_POS)
188 // QIEStream::CHECKSUM_POS);
189 if (checksum != reference_checksum)
190 ldmx_log(fatal) << "Got checksum mismatch: expected "
191 << (int)reference_checksum << ", stream says " << checksum;
192 if (is_ci_dunsync) ldmx_log(debug) << "Found unsynced CIDs!";
193 if (is_ci_dskipped) ldmx_log(fatal) << "Found skipped CIDs!";
194
195 /* -- TS event header done; read the channel contents -- */
196 std::vector<trigscint::TrigScintQIEDigis> out_digis;
197 std::map<int, std::vector<int>> ad_cmap;
198 std::map<int, std::vector<int>> td_cmap;
199
200 // read in words from the stream. line them up per channel and time sample.
201 // channels are in the electronics ordering
202 int i_wstart =
203 std::max(std::max(QIEStream::ERROR_POS, QIEStream::CHECKSUM_POS),
204 QIEStream::TRIGID_POS + (QIEStream::TRIGID_LEN_BYTES)) +
205 1;
206 // make sure we're at end of header
207 int n_words = n_samp * n_channels_ * 2 + i_wstart;
208 // 1 ADC, 1 TDC per channel per sample,
209 // + the words in the header
210 int i_word = i_wstart;
211 ldmx_log(debug) << "Event parsing starts at vector idx " << i_wstart
212 << " and nWords = " << n_words;
213 // outer loop: over nSamples
214 // inner loop over nChannels to get ADCs, then repeat to get TDCs
215 for (int i_s = 0; i_s < n_samp; i_s++) {
216 for (int i_q = 0; i_q < n_channels_; i_q++) {
217 if (i_word >= n_words) {
218 ldmx_log(fatal)
219 << "More words than expected! Breaking ADC loop in sample " << i_s
220 << " at iQ = " << i_q;
221 break;
222 }
223 uint8_t val = event_stream.at(i_word);
224 if (val > 0) { // add only the digis with non-zero ADC value
225 ldmx_log(debug) << "got ADC value " << (unsigned)val
226 << " at channel (elec) idx " << i_q;
227 if (ad_cmap.find(i_q) == ad_cmap.end()) { // we have a new channel
228 std::vector<int> adcs(n_samp, 0);
229 ad_cmap.insert(std::pair<int, std::vector<int>>(i_q, adcs));
230 }
231 ad_cmap[i_q].at(i_s) = val;
232 }
233 i_word++;
234 }
235 for (int i_q = 0; i_q < n_channels_; i_q++) {
236 if (i_word >= n_words) {
237 ldmx_log(debug)
238 << "More words than expected! Breaking TDC loop in sample " << i_s
239 << " at iQ = " << i_q;
240 break;
241 }
242 uint8_t val = event_stream.at(i_word);
243 if (val > 0) { // TODO: check if this channel is also present in ADC map?
244 // in the end?
245 ldmx_log(debug) << "got TDC value " << (unsigned)val
246 << " at channel (elec) idx " << i_q;
247 ;
248 if (td_cmap.find(i_q) == td_cmap.end()) { // we have a new channel
249 std::vector<int> tdcs(n_samp, 0);
250 td_cmap.insert(std::pair<int, std::vector<int>>(i_q, tdcs));
251 }
252 // this is LETDC; only the two most significant bits included
253 // they are shipped as least significant bits --> shift them
254 // TDCmap[iQ].at(iS) = (val + 1) * 16; // want LE TDC = 3 to correspond
255 // to
256 // 64 > 49 (which is maxTDC in sim)
257 td_cmap[i_q].at(i_s) = val; // have full 6-bit TDC at SLAC
258 }
259 i_word++;
260 }
261 ldmx_log(debug) << "Done with sample " << i_s;
262 }
263
264 ldmx_log(debug) << "Done reading in header, ADC and TDC for event "
265 << trigger_id;
266 for (std::map<int, std::vector<int>>::iterator itr = ad_cmap.begin();
267 itr != ad_cmap.end(); ++itr) {
268 TrigScintQIEDigis digi;
269 digi.setADC(itr->second);
270 if (channel_map_.find(itr->first) == channel_map_.end()) {
271 ldmx_log(fatal)
272 << "Couldn't find the bar ID corresponding to electronics ID "
273 << itr->first << "!! Skipping.";
274 continue;
275 }
276 int bar = channel_map_[itr->first];
277 digi.setElecID(itr->first);
278 digi.setChanID(bar);
279 digi.setTDC(td_cmap[itr->first]);
280 digi.setTimeSinceSpill(time_spill);
281 if (bar == 0)
282 ldmx_log(debug) << "for bar 0, got time since spill "
283 << digi.getTimeSinceSpill();
284 out_digis.push_back(digi);
285 ldmx_log(debug) << "Iterator points to key " << itr->first
286 << " and mapped channel supposedly is " << bar;
287 ldmx_log(debug) << "Made digi with elecID = " << digi.getElecID()
288 << ", barID = " << digi.getChanID() << ", third adc value "
289 << digi.getADC().at(2) << " and third tdc "
290 << digi.getTDC().at(2);
291 }
292
293 event.add(output_collection_, out_digis);
294}
ldmx::EventHeader & getEventHeader()
Get the event header.
Definition Event.h:57
int getEventNumber() const
Return the event number.
Definition EventHeader.h:78

References trigscint::TrigScintQIEDigis::getADC(), trigscint::TrigScintQIEDigis::getChanID(), trigscint::TrigScintQIEDigis::getElecID(), framework::Event::getEventHeader(), ldmx::EventHeader::getEventNumber(), trigscint::TrigScintQIEDigis::getTDC(), trigscint::TrigScintQIEDigis::getTimeSinceSpill(), trigscint::TrigScintQIEDigis::setADC(), trigscint::TrigScintQIEDigis::setChanID(), trigscint::TrigScintQIEDigis::setElecID(), trigscint::TrigScintQIEDigis::setTDC(), and trigscint::TrigScintQIEDigis::setTimeSinceSpill().

Member Data Documentation

◆ channel_map_

std::map<int, int> trigscint::QIEDecoder::channel_map_
private

Definition at line 37 of file QIEDecoder.h.

◆ channel_map_file_

std::ifstream trigscint::QIEDecoder::channel_map_file_
private

Definition at line 36 of file QIEDecoder.h.

◆ channel_map_file_name_

std::string trigscint::QIEDecoder::channel_map_file_name_
private

the channel mapping

Definition at line 35 of file QIEDecoder.h.

Referenced by configure().

◆ input_collection_

std::string trigscint::QIEDecoder::input_collection_
private

Definition at line 40 of file QIEDecoder.h.

◆ input_pass_name_

std::string trigscint::QIEDecoder::input_pass_name_
private

Definition at line 42 of file QIEDecoder.h.

◆ is_real_data_

bool trigscint::QIEDecoder::is_real_data_ {false}
private

Definition at line 49 of file QIEDecoder.h.

49{false};

◆ n_channels_

int trigscint::QIEDecoder::n_channels_ {50}
private

Definition at line 45 of file QIEDecoder.h.

45{50};

◆ n_samples_

int trigscint::QIEDecoder::n_samples_ {5}
private

Definition at line 47 of file QIEDecoder.h.

47{5};

◆ output_collection_

std::string trigscint::QIEDecoder::output_collection_
private

Definition at line 41 of file QIEDecoder.h.


The documentation for this class was generated from the following files: