All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pmtArtdaqFragmentProducer_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: pmtArtdaqFragmentProducer
3 // Plugin Type: producer (Unknown Unknown)
4 // File: pmtArtdaqFragmentProducer_module.cc
5 //
6 // Generated at Mon Feb 7 14:18:34 2022 by Patrick Green using cetskelgen
7 // from version .
8 
9 // Module to convert simulated PMT waveforms into artdaq fragment format
10 // Input: PMT waveforms and output from hardware trigger producer (pmtTriggerProducer_module.cc)
11 // For each hardware trigger, creates and saves CAEN1730 art-daq fragments for each PMT waveform.
12 // Time range: -1us to +9us from hardware trigger time. 8 fragments per trigger, each containing 15 PMT waveforms (channels 0-14)
13 // Sets trigger time to 0.5 seconds +- PMT trigger time; and adds step function for beam time (relative to trigger) (channel 15)
14 // Output: adds std::vector<artdaq::Fragment> containing the fragments from each event
15 // To do -- change timerange offset and trigger time offset to be fhicl parameters + any other hardcoded pieces
16 ////////////////////////////////////////////////////////////////////////
17 
18 #include "art/Framework/Core/EDProducer.h"
19 #include "art/Framework/Core/ModuleMacros.h"
20 #include "art/Framework/Principal/Event.h"
21 #include "art/Framework/Principal/Handle.h"
22 #include "art/Framework/Principal/Run.h"
23 #include "art/Framework/Principal/SubRun.h"
24 #include "canvas/Utilities/InputTag.h"
25 #include "fhiclcpp/ParameterSet.h"
26 #include "messagefacility/MessageLogger/MessageLogger.h"
27 #include "art_root_io/TFileService.h"
28 
29 // artdaq includes
30 #include "sbndaq-artdaq-core/Overlays/Common/CAENV1730Fragment.hh"
31 #include "sbndaq-artdaq-core/Overlays/FragmentType.hh"
32 #include "artdaq-core/Data/Fragment.hh"
33 
34 // LArSoft includes
37 
38 // SBN/SBND includes
41 
42 // ROOT includes
43 #include "TFile.h"
44 #include "TH1D.h"
45 
46 // random numbers
47 #include "nurandom/RandomUtils/NuRandomService.h"
48 #include "CLHEP/Random/RandFlat.h"
49 
50 #include <memory>
51 #include <vector>
52 #include <string>
53 #include <iostream>
54 #include <ctime>
55 
56 namespace sbnd {
57  namespace trigger {
59  }
60 }
61 
62 
63 class sbnd::trigger::pmtArtdaqFragmentProducer : public art::EDProducer {
64 public:
65  explicit pmtArtdaqFragmentProducer(fhicl::ParameterSet const& p);
66  // The compiler-generated destructor is fine for non-base
67  // classes without bare pointers or other resource use.
68 
69  // Plugins should not be copied or assigned.
74 
75  // Required functions.
76  void produce(art::Event& e) override;
77 
78 private:
79 
80  // Declare member data here.
81 
82  // fhicl parameters
83  std::string fInputModuleNameWvfm;
85  int fBaseline; // baseline in simulation, default 8000 ADC (for expanding waveforms only, when not fully simulated)
86  int fMultiplicityThreshold; // number of PMT pairs in hardware trigger to pass
88  uint32_t nChannelsFrag;
89  uint32_t wfm_length; // ~10us, 2ns tick
90  bool fVerbose;
91 
92  // event information
93  int fRun, fSubrun;
94  art::EventNumber_t fEvent;
95 
96  // PD information
97  opdet::sbndPDMapAlg pdMap; // photon detector map
98  std::vector<unsigned int> channelList;
99 
100  // waveforms
101  std::vector<std::vector<short>> wvf_channel;
102 
103  // sampling rate
104  double fSampling;
105 
106  // services
107  art::ServiceHandle<art::TFileService> tfs;
108 
109  // random numbers
110  CLHEP::HepRandomEngine& fTriggerTimeEngine;
111 
112 };
113 
114 
116  : EDProducer{p},
117  fInputModuleNameWvfm(p.get<std::string>("InputModuleNameWvfm")),
118  fInputModuleNameTrigger(p.get<std::string>("InputModuleNameTrigger")),
119  fBaseline(p.get<int>("Baseline",8000)),
120  fMultiplicityThreshold(p.get<int>("MultiplicityThreshold")),
121  fBeamWindowLength(p.get<double>("BeamWindowLength", 1.6)),
122  nChannelsFrag(p.get<double>("nChannelsFrag", 15)),
123  wfm_length(p.get<double>("WfmLength", 5120)),
124  fVerbose(p.get<bool>("Verbose", false)),
125  fTriggerTimeEngine(art::ServiceHandle<rndm::NuRandomService>{}->createEngine(*this, "HepJamesRandom", "trigger", p, "SeedTriggerTime"))
126  // More initializers here.
127 {
128  // Call appropriate produces<>() functions here.
129  produces< std::vector<artdaq::Fragment> >();
130 
131  // get clock
132  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
133  fSampling = clockData.OpticalClock().Frequency(); // MHz
134 
135  // build PD map and channel list
136  auto subsetCondition = [](auto const& i)->bool { return i["pd_type"] == "pmt_coated" || i["pd_type"] == "pmt_uncoated"; };
137  auto pmtMap = pdMap.getCollectionFromCondition(subsetCondition);
138  if (fVerbose) std::cout << "Number of PDs selected: \t" << pmtMap.size() << "\n";
139  for(auto const& i:pmtMap){
140  channelList.push_back(i["channel"]);
141  }
142 
143 }
144 
146 {
147  // Implementation of required member function here.
148 
149  // event information
150  fRun = e.run();
151  fSubrun = e.subRun();
152  fEvent = e.id().event();
153 
154  if (fVerbose) std::cout << "Processing Run: " << fRun << ", Subrun: " << fSubrun << ", Event: " << fEvent << std::endl;
155 
156  // access PMT waveforms and hardware trigger information
157  art::Handle< std::vector< raw::OpDetWaveform > > wvfmHandle;
158  art::Handle< std::vector< sbnd::comm::pmtTrigger > > triggerHandle;
159  e.getByLabel(fInputModuleNameWvfm, wvfmHandle);
160  e.getByLabel(fInputModuleNameTrigger, triggerHandle);
161 
162  if(!wvfmHandle.isValid()) {
163  throw art::Exception(art::errors::Configuration)
164  << "Could not find any waveforms, input must contain OpDetWaveforms." << "\n";
165  }
166  if(!triggerHandle.isValid()) {
167  throw art::Exception(art::errors::Configuration)
168  << "Could not find any PMT hardware trigger object, must run PMT trigger producer before running this module." << "\n";
169  }
170 
171  // create empty vectors to hold waveforms for each channel
172  double fMinStartTime = -1510.0;//in us
173  double fMaxEndTime = 1510.0;//in us
174 
175  for(auto const& wvf : (*wvfmHandle)) {
176  double fChNumber = wvf.ChannelNumber();
177  std::string opdetType = pdMap.pdType(fChNumber);
178  // only look at pmts
179  if (opdetType != "pmt_coated" && opdetType != "pmt_uncoated") continue;
180  if (wvf.TimeStamp() < fMinStartTime){ fMinStartTime = wvf.TimeStamp(); }
181  if ((double(wvf.size()) / fSampling + wvf.TimeStamp()) > fMaxEndTime){ fMaxEndTime = double(wvf.size()) / fSampling + wvf.TimeStamp();}
182  }
183 
184  if (fVerbose){std::cout<<"MinStartTime: "<<fMinStartTime<<" MaxEndTime: "<<fMaxEndTime<<std::endl;}
185 
186  std::vector<short> wvf_0; wvf_0.reserve((int)(3020*1e6/2));
187  for (double i = fMinStartTime; i<fMaxEndTime+(1./fSampling); i+=(1./fSampling)){
188  wvf_0.push_back(fBaseline);
189  }
190  for (size_t i = 0; i < channelList.size(); i++){
191  wvf_channel.push_back(wvf_0);
192  }
193 
194  // counters
195  int num_pmt_wvf = 0;
196 
197  // loop through waveform handles
198  size_t wvf_id = -1;
199  size_t hist_id = -1;
200  for(auto const& wvf : (*wvfmHandle)) {
201  wvf_id++;
202  double fChNumber = wvf.ChannelNumber();
203  std::string opdetType = pdMap.pdType(fChNumber);
204 
205  // only look at pmts
206  if (opdetType != "pmt_coated" && opdetType != "pmt_uncoated") continue;
207 
208  num_pmt_wvf++;
209 
210  double fStartTime = wvf.TimeStamp(); // in us
211  double fEndTime = double(wvf.size()) / fSampling + fStartTime; // in us
212 
213  // create full waveform
214  std::vector<short> wvf_full; wvf_full.reserve((short)(3020*1e6/2));
215 
216  if (fStartTime > fMinStartTime){
217  for (double i = fStartTime-fMinStartTime; i>0.; i-=(1./fSampling)){
218  wvf_full.push_back(fBaseline);
219  }
220  }
221 
222  for(unsigned int i = 0; i < wvf.size(); i++) {
223  wvf_full.push_back(wvf[i]);
224  }
225 
226  if (fEndTime < fMaxEndTime){
227  for (double i = fMaxEndTime-fEndTime; i>0.; i-=(1./fSampling)){
228  wvf_full.push_back(fBaseline);
229  }
230  }
231 
232  // combine waveform with any other waveforms from same channel
233  int i_ch = -1.;
234  auto ich = std::find(channelList.begin(), channelList.end(), fChNumber);
235  if (ich != channelList.end()){
236  i_ch = ich - channelList.begin();
237  }
238  if (wvf_channel.at(i_ch).size() < wvf_full.size()){
239  if (fVerbose) std::cout<<"Full waveform -- Previous Channel" << fChNumber <<" Size: "<<wvf_channel.at(i_ch).size()<<"New Channel" << fChNumber <<" Size: "<<wvf_full.size()<<std::endl;
240  for(unsigned int i = wvf_channel.at(i_ch).size(); i < wvf_full.size(); i++) {
241  wvf_channel.at(i_ch).push_back(fBaseline);
242  }
243  }
244  for(unsigned int i = 0; i < wvf_full.size(); i++) {
245  wvf_channel.at(i_ch)[i] += (wvf_full[i] - fBaseline);
246  }
247 
248  hist_id++;
249 
250  wvfmHandle.clear();
251  } // waveform handle loop
252 
253  // access hardware trigger information
254  std::vector<size_t> triggerIndex;
255  for(auto const& trigger : (*triggerHandle)) {
256  for (size_t idx = 0; idx < trigger.numPassed.size(); idx++) {
257  if (trigger.numPassed[idx] >= fMultiplicityThreshold) {
258  // save index
259  triggerIndex.push_back(idx);
260  // skip ahead by 5120 samples (downsampled by 4) before checking again
261  idx += 1280;
262  }
263  }
264  } // trigger handle loop
265 
266  if (fVerbose) std::cout << "Number of PMT hardware triggers found: " << triggerIndex.size() << std::endl;
267 
268  // fragments vector
269  std::unique_ptr<std::vector<artdaq::Fragment>> vecFrag = std::make_unique<std::vector<artdaq::Fragment>>();
270 
271  // set properties of fragment that are common to event
272  uint32_t nChannelsTotal = channelList.size();
273  //uint32_t nChannelsFrag = 15;
274  uint32_t nFrag = (uint32_t)nChannelsTotal/nChannelsFrag;
275  //uint32_t wfm_length = 5120; // ~10us, 2ns tick
276 
277  // fragment properties
278  uint32_t sequenceIDVal = fEvent;
279 
280  // create and populate common metadata
281  sbndaq::CAENV1730FragmentMetadata metadata;
282  metadata.nChannels = nChannelsFrag + 1; // 15 PMT channels + final channel to store beam window / trigger information
283  metadata.nSamples = wfm_length;
284 
285  // fragment handle properties
286  uint32_t eventCounterVal = fEvent;
287  uint32_t boardIDVal = 0;
288  uint32_t triggerTimeTagVal = (uint32_t)CLHEP::RandFlat::shoot(&fTriggerTimeEngine, 0, 1e9);
289  uint32_t eventSizeVal = ((wfm_length * (nChannelsFrag+1)) * sizeof(uint16_t) + sizeof(sbndaq::CAENV1730EventHeader)) / sizeof(uint32_t);
290 
291  // loop over PMT hardware triggers
292  for (auto wvfIdx : triggerIndex) {
293 
294  // index in full waveform, 2ns tick
295  size_t trigIdx = wvfIdx*4;
296  size_t startIdx = trigIdx-500; // -1us
297 
298  // determine and set timestamp for particular trigger
299  double triggerTime = fMinStartTime + wvfIdx*0.008; // in us
300  double timestampVal = 0.5 + (triggerTime*1e-6); // in seconds // std::time(nullptr); // current time
301  metadata.timeStampSec = (uint32_t)timestampVal;
302  metadata.timeStampNSec = (uint32_t)(timestampVal*1e9);
303 
304  // create fragments to hold waveforms, set properties and populate
305  // 15 PMTs stored per fragment, 120/15 = 8 fragments per trigger
306  for (size_t counter = 0; counter < nFrag; counter++) {
307 
308  // create fragment
309  const auto fragment_datasize_bytes = metadata.ExpectedDataSize();
310  uint32_t fragmentIDVal = counter;
311  auto fragment_uptr = artdaq::Fragment::FragmentBytes(fragment_datasize_bytes, sequenceIDVal, fragmentIDVal, sbndaq::detail::FragmentType::CAENV1730, metadata); // unique pointer
312  fragment_uptr->setTimestamp(timestampVal);
313 
314  // populate fragment header
315  auto header_ptr = reinterpret_cast<sbndaq::CAENV1730EventHeader*>(fragment_uptr->dataBeginBytes());
316 
317  header_ptr->eventCounter = eventCounterVal;
318  header_ptr->boardID = boardIDVal;
319  header_ptr->triggerTimeTag = triggerTimeTagVal; // ns // set timetag as random value for event
320  header_ptr->eventSize = eventSizeVal;
321 
322  // populate waveforms
323  // populate fragment with waveform
324  uint16_t* data_begin = reinterpret_cast<uint16_t*>(fragment_uptr->dataBeginBytes() + sizeof(sbndaq::CAENV1730EventHeader));
325  uint16_t* value_ptr = data_begin;
326  uint16_t value = 0;
327  size_t ch_offset = 0;
328 
329  // loop over channels
330  for (size_t i_ch = 0; i_ch < nChannelsFrag; i_ch++) {
331  ch_offset = (size_t)(i_ch*wfm_length);
332  // loop over waveform
333  for (size_t i_t = 0; i_t < wfm_length; i_t++) {
334  // set value
335  value = wvf_channel[counter*nChannelsFrag + i_ch][startIdx+i_t];
336  value_ptr = data_begin + ch_offset + i_t;
337  *value_ptr = value;
338  }
339  }
340 
341  // create add beam window trigger waveform
342  ch_offset = (size_t)(nChannelsFrag*wfm_length);
343  size_t beamStartIdx = abs(fMinStartTime)*1000/2;
344  size_t beamEndIdx = beamStartIdx + fBeamWindowLength*1000/2;
345  // loop over waveform
346  for (size_t i_t = 0; i_t < wfm_length; i_t++) {
347  // set value
348  if (startIdx + i_t >= beamStartIdx && startIdx + i_t <= beamEndIdx) value = 1;
349  else value = 0;
350  value_ptr = data_begin + ch_offset + i_t;
351  *value_ptr = value;
352  }
353 
354  // add fragment to vector
355  vecFrag->push_back(*fragment_uptr);
356  }
357  }
358 
359  if(fVerbose) std::cout << "Fragments written: " << vecFrag->size() << std::endl;
360 
361  // add fragments to event
362  e.put(std::move(vecFrag));
363 
364  // clear variables
365  wvf_channel.clear();
366  wvf_channel.shrink_to_fit();
367 }
368 
pdgs p
Definition: selectors.fcl:22
pmtArtdaqFragmentProducer & operator=(pmtArtdaqFragmentProducer const &)=delete
BEGIN_PROLOG pmtArtdaqFragmentProducer
T abs(T value)
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
Definition: counter.h:285
do i e
stream1 can override from command line with o or output services user sbnd
Sample_t fBaseline
Waveform baseline [ADC counts].
temporary value
BEGIN_PROLOG could also be cout