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"
29 #include "sbndaq-artdaq-core/Overlays/Common/CAENV1730Fragment.hh"
30 #include "sbndaq-artdaq-core/Overlays/FragmentType.hh"
31 #include "artdaq-core/Data/Fragment.hh"
32 #include "artdaq-core/Data/ContainerFragment.hh"
66 void produce(art::Event&
e)
override;
89 art::ServiceHandle<art::TFileService>
tfs;
123 is_persistable_(
p.get<
bool>(
"is_persistable",
true) ? art::Persistable::Yes : art::Persistable::No),
124 fTriggerTimeOffset(
p.get<
double>(
"TriggerTimeOffset", 0.5)),
125 fBeamWindowLength(
p.get<
double>(
"BeamWindowLength", 1.6)),
126 fWvfmLength(
p.get<uint32_t>(
"WvfmLength", 5120)),
127 fVerbose(
p.get<
bool>(
"Verbose",
false)),
128 fSaveHists(
p.get<
bool>(
"SaveHists",
false)),
129 fBaselineAlgo(
p.get<std::string>(
"BaselineAlgo",
"estimate")),
130 fInputBaseline(
p.get<
double>(
"InputBaseline", 8000)),
131 fInputBaselineSigma(
p.get<
double>(
"InputBaselineSigma", 2)),
132 fADCThreshold(
p.get<
double>(
"ADCThreshold", 7960)),
133 fFindPulses(
p.get<
bool>(
"FindPulses",
false)),
134 fPEArea(
p.get<
double>(
"PEArea", 66.33))
138 produces< sbnd::trigger::pmtSoftwareTrigger >(
"", is_persistable_);
140 beamWindowStart = fTriggerTimeOffset*1e9;
141 beamWindowEnd = beamWindowStart + fBeamWindowLength*1000;
144 auto subsetCondition = [](
auto const& i)->
bool {
return i[
"pd_type"] ==
"pmt_coated" || i[
"pd_type"] ==
"pmt_uncoated"; };
145 auto pmtMap = pdMap.getCollectionFromCondition(subsetCondition);
146 for(
auto const& i:pmtMap){
147 channelList.push_back(i[
"channel"]);
157 fSubrun = e.subRun();
158 fEvent = e.id().event();
160 if (fVerbose)
std::cout <<
"Processing Run: " << fRun <<
", Subrun: " << fSubrun <<
", Event: " << fEvent << std::endl;
163 foundBeamTrigger =
false;
165 fWvfmsVec.clear(); fWvfmsVec.resize(15*8);
166 fpmtInfoVec.clear(); fpmtInfoVec.resize(15*8);
170 std::vector<art::Handle<artdaq::Fragments>> fragmentHandles = e.getMany<std::vector<artdaq::Fragment>>();
173 for (
auto &handle : fragmentHandles) {
174 if (!handle.isValid() || handle->size() == 0)
continue;
175 if (handle->front().type()==sbndaq::detail::FragmentType::CAENV1730) {
176 if (fVerbose)
std::cout <<
"Found " << handle->size() <<
" CAEN1730 fragments" << std::endl;
180 size_t beamFragmentIdx = 9999;
181 for (
size_t fragmentIdx = 0; fragmentIdx < handle->size(); fragmentIdx += 8) {
182 checkCAEN1730FragmentTimeStamp(handle->at(fragmentIdx));
183 if (foundBeamTrigger) {
184 beamFragmentIdx = fragmentIdx;
185 if (fVerbose)
std::cout <<
"Found fragment in time with beam at index: " << beamFragmentIdx << std::endl;
190 if (foundBeamTrigger && beamFragmentIdx != 9999) {
191 for (
size_t fragmentIdx = beamFragmentIdx; fragmentIdx < beamFragmentIdx+8; fragmentIdx++) {
192 analyzeCAEN1730Fragment(handle->at(fragmentIdx));
200 std::unique_ptr<sbnd::trigger::pmtSoftwareTrigger> pmtSoftwareTriggerMetrics = std::make_unique<sbnd::trigger::pmtSoftwareTrigger>();
202 if (foundBeamTrigger && fWvfmsFound) {
206 double triggerTimeStamp = fTriggerTime - beamWindowStart;
208 if (fVerbose)
std::cout <<
"Saving trigger timestamp: " << triggerTimeStamp <<
" ns" << std::endl;
213 int nAboveThreshold = 0;
216 int beamStartBin = (triggerTimeStamp >= 1000)? 0 :
int(500 -
abs((triggerTimeStamp-1000)/2));
217 int beamEndBin = (triggerTimeStamp >= 1000)?
int(500 + (fBeamWindowLength*1e3 - triggerTimeStamp)/2) : (beamStartBin + (fBeamWindowLength*1e3)/2);
220 for (
int i_ch = 0; i_ch < 120; ++i_ch){
221 auto &
pmtInfo = fpmtInfoVec.at(i_ch);
222 auto wvfm = fWvfmsVec[i_ch];
229 else if (fBaselineAlgo ==
"estimate") estimateBaseline(i_ch);
232 for (
int bin = beamStartBin;
bin < beamEndBin; ++
bin){
233 auto adc = wvfm[
bin];
234 if (adc < fADCThreshold){ nAboveThreshold++;
break; }
239 auto prompt_window = std::vector<uint16_t>(wvfm.begin()+500, wvfm.begin()+1000);
240 auto prelim_window = std::vector<uint16_t>(wvfm.begin()+beamStartBin, wvfm.begin()+500);
241 if (fFindPulses ==
false){
242 double ch_promptPE = (baseline-(*std::min_element(prompt_window.begin(), prompt_window.end())))/8;
243 double ch_prelimPE = (baseline-(*std::min_element(prelim_window.begin(), prelim_window.end())))/8;
244 promptPE += ch_promptPE;
245 prelimPE += ch_prelimPE;
249 if (fFindPulses ==
true){
250 SimpleThreshAlgo(i_ch);
252 if (pulse.t_start > 500 && pulse.t_end < 550) promptPE+=pulse.pe;
253 if ((triggerTimeStamp) >= 1000){
if (pulse.t_end < 500) prelimPE+=pulse.pe; }
254 else if (triggerTimeStamp < 1000){
255 if (pulse.t_start > (500 -
abs((triggerTimeStamp-1000)/2)) && pulse.t_end < 500) prelimPE+=pulse.pe;
262 pmtSoftwareTriggerMetrics->
promptPE = promptPE;
263 pmtSoftwareTriggerMetrics->
prelimPE = prelimPE;
264 if (fVerbose)
std::cout <<
"nPMTs Above Threshold: " << nAboveThreshold << std::endl;
265 if (fVerbose)
std::cout <<
"prompt pe: " << promptPE << std::endl;
266 if (fVerbose)
std::cout <<
"prelim pe: " << prelimPE << std::endl;
269 if (fSaveHists ==
true){
271 for (
size_t i_wvfm = 0; i_wvfm < fWvfmsVec.size(); ++i_wvfm){
272 std::vector<uint16_t> wvfm = fWvfmsVec[i_wvfm];
275 histname.str(std::string());
276 histname <<
"event_" << fEvent
277 <<
"_channel_" << i_wvfm;
278 double StartTime = ((fTriggerTime-beamWindowStart) - 500)*1e-3;
279 double EndTime = StartTime + (5210*2)*1e-03;
280 TH1D *wvfmHist =
tfs->make< TH1D >(histname.str().c_str(),
"Raw Waveform", wvfm.size(), StartTime, EndTime);
281 wvfmHist->GetXaxis()->SetTitle(
"t (#mus)");
282 for(
unsigned int i = 0; i < wvfm.size(); i++) {
283 wvfmHist->SetBinContent(i + 1, (
double)wvfm[i]);
290 if (fVerbose)
std::cout <<
"Beam and wvfms not found" << std::endl;
294 pmtSoftwareTriggerMetrics->
promptPE = -9999;
295 pmtSoftwareTriggerMetrics->
prelimPE = -9999;
297 e.put(std::move(pmtSoftwareTriggerMetrics));
304 sbndaq::CAENV1730Fragment bb(frag);
305 auto const*
md = bb.Metadata();
308 uint32_t timestamp =
md->timeStampNSec;
312 const uint16_t* data_begin =
reinterpret_cast<const uint16_t*
>(frag.dataBeginBytes()
313 +
sizeof(sbndaq::CAENV1730EventHeader));
314 const uint16_t* value_ptr = data_begin;
317 size_t ch_offset = (size_t)(15*fWvfmLength);
318 size_t tr_offset = fTriggerTimeOffset*1e3;
320 value_ptr = data_begin + ch_offset + tr_offset;
321 value = *(value_ptr);
323 if (value == 1 && timestamp >= beamWindowStart && timestamp <= beamWindowEnd) {
324 foundBeamTrigger =
true;
325 fTriggerTime = timestamp;
332 int fragId =
static_cast<int>(frag.fragmentID());
335 const uint16_t* data_begin =
reinterpret_cast<const uint16_t*
>(frag.dataBeginBytes()
336 +
sizeof(sbndaq::CAENV1730EventHeader));
337 const uint16_t* value_ptr = data_begin;
341 size_t nChannels = 15;
342 size_t ch_offset = 0;
345 for (
size_t i_ch = 0; i_ch < nChannels; ++i_ch){
346 fWvfmsVec[i_ch + nChannels*fragId].resize(fWvfmLength);
347 ch_offset = (size_t)(i_ch * fWvfmLength);
349 for(
size_t i_t = 0; i_t < fWvfmLength; ++i_t){
350 value_ptr = data_begin + ch_offset + i_t;
351 value = *(value_ptr);
352 fWvfmsVec[i_ch + nChannels*fragId][i_t] =
value;
358 auto wvfm = fWvfmsVec[i_ch];
359 auto &
pmtInfo = fpmtInfoVec[i_ch];
361 std::vector<uint16_t> subset = std::vector<uint16_t>(wvfm.begin(), wvfm.begin()+250);
362 double subset_mean = (std::accumulate(subset.begin(), subset.end(), 0))/(subset.size());
364 for (
size_t i=0; i<subset.size();i++){ val += (subset[i] - subset_mean)*(subset[i] - subset_mean);}
365 double subset_stddev = sqrt(val/subset.size());
368 if (subset_stddev > 3){
369 val = 0; subset.clear(); subset_stddev = 0;
370 subset = std::vector<uint16_t>(wvfm.end()-500, wvfm.end());
371 subset_mean = (std::accumulate(subset.begin(), subset.end(), 0))/(subset.size());
372 for (
size_t i=0; i<subset.size();i++){ val += (subset[i] - subset_mean)*(subset[i] - subset_mean);}
373 subset_stddev = sqrt(val/subset.size());
380 auto wvfm = fWvfmsVec[i_ch];
381 auto &
pmtInfo = fpmtInfoVec[i_ch];
389 double start_adc_thres = 5, end_adc_thres = 2;
390 double nsigma_start = 5, nsigma_end = 3;
392 auto start_threshold = ( start_adc_thres > (nsigma_start * baseline_sigma) ? (baseline-start_adc_thres) : (baseline-(nsigma_start * baseline_sigma)));
393 auto end_threshold = ( end_adc_thres > (nsigma_end * baseline_sigma) ? (baseline - end_adc_thres) : (baseline - (nsigma_end * baseline_sigma)));
395 std::vector<sbnd::trigger::pmtPulse> pulse_vec;
398 for (
auto const &adc : wvfm){
399 if ( !fire && ((
double)adc) <= start_threshold ){
405 if( fire && ((
double)adc) > end_threshold ){
408 pulse.
t_end = counter < ((int)wvfm.size()) ? counter : counter - 1;
409 pulse_vec.push_back(pulse);
414 pulse.
area += (baseline-(double)adc);
415 if (pulse.
peak > (baseline-(
double)adc)) {
416 pulse.
peak = (baseline-(double)adc);
425 pulse.
t_end = counter - 1;
426 pulse_vec.push_back(pulse);
void estimateBaseline(int i_ch)
BEGIN_PROLOG pmtSoftwareTriggerProducer
void analyzeCAEN1730Fragment(const artdaq::Fragment &frag)
pmtSoftwareTriggerProducer(fhicl::ParameterSet const &p)
opdet::sbndPDMapAlg pdMap
double fInputBaselineSigma
std::vector< unsigned int > channelList
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
art::Persistable is_persistable_
std::vector< sbnd::trigger::pmtInfo > fpmtInfoVec
void SimpleThreshAlgo(int i_ch)
pmtSoftwareTriggerProducer & operator=(pmtSoftwareTriggerProducer const &)=delete
void produce(art::Event &e) override
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
std::vector< std::vector< uint16_t > > fWvfmsVec
double fTriggerTimeOffset
std::vector< sbnd::trigger::pmtPulse > pulseVec
std::stringstream histname
std::string fBaselineAlgo
stream1 can override from command line with o or output services user sbnd
art::ServiceHandle< art::TFileService > tfs
art::EventNumber_t fEvent
BEGIN_PROLOG could also be cout
void checkCAEN1730FragmentTimeStamp(const artdaq::Fragment &frag)
art::ServiceHandle< art::TFileService > tfs