10 #include "art/Framework/Core/EDProducer.h"
11 #include "art/Framework/Core/ModuleMacros.h"
12 #include "art/Framework/Principal/Event.h"
13 #include "art/Framework/Principal/Handle.h"
14 #include "art/Framework/Principal/Run.h"
15 #include "art/Framework/Principal/SubRun.h"
16 #include "canvas/Utilities/InputTag.h"
17 #include "fhiclcpp/ParameterSet.h"
18 #include "messagefacility/MessageLogger/MessageLogger.h"
20 #include "sbndaq-artdaq-core/Overlays/Common/BernCRTFragmentV2.hh"
21 #include "sbndaq-artdaq-core/Overlays/Common/CAENV1730Fragment.hh"
22 #include "sbndaq-artdaq-core/Overlays/FragmentType.hh"
23 #include "artdaq-core/Data/Fragment.hh"
24 #include "artdaq-core/Data/ContainerFragment.hh"
121 is_persistable_(
p.get<
bool>(
"is_persistable",
true) ? art::Persistable::Yes : art::Persistable::No),
122 fBeamWindowStart(
p.get<
int>(
"BeamWindowStart",320000)),
123 fBeamWindowEnd(
p.get<
int>(
"BeamWindowEnd",350000)),
124 fVerbose(
p.get<
bool>(
"Verbose",
false)),
125 fcrt_metrics(
p.get<
bool>(
"crt_metrics",
true)),
126 fpmt_metrics(
p.get<
bool>(
"pmt_metrics",
true)),
127 fTriggerTimeOffset(
p.get<
double>(
"TriggerTimeOffset", 0.5)),
128 fBeamWindowLength(
p.get<
double>(
"BeamWindowLength", 1.6)),
129 fWvfmLength(
p.get<uint32_t>(
"WvfmLength", 5120)),
130 fBaselineAlgo(
p.get<std::string>(
"BaselineAlgo",
"estimate")),
131 fInputBaseline(
p.get<
double>(
"InputBaseline", 8000)),
132 fInputBaselineSigma(
p.get<
double>(
"InputBaselineSigma", 2)),
133 fADCThreshold(
p.get<
double>(
"ADCThreshold", 7960)),
134 fFindPulses(
p.get<
bool>(
"FindPulses",
false)),
135 fPEArea(
p.get<
double>(
"PEArea", 66.33))
138 produces< sbndaq::CRTmetric >(
"", is_persistable_);
140 produces< sbnd::trigger::pmtSoftwareTrigger >(
"", is_persistable_);
142 beamWindowStart = fTriggerTimeOffset*1e9;
143 beamWindowEnd = beamWindowStart + fBeamWindowLength*1000;
146 auto subsetCondition = [](
auto const& i)->
bool {
return i[
"pd_type"] ==
"pmt_coated" || i[
"pd_type"] ==
"pmt_uncoated"; };
147 auto pmtMap = pdMap.getCollectionFromCondition(subsetCondition);
148 for(
auto const& i:pmtMap){
149 channelList.push_back(i[
"channel"]);
160 fSubrun = evt.subRun();
161 fEvent = evt.event();
163 if (fVerbose)
std::cout <<
"Processing: Run " << fRun <<
", Subrun " << fSubrun <<
", Event " << fEvent << std::endl;
166 std::unique_ptr<sbndaq::CRTmetric> CRTMetricInfo = std::make_unique<sbndaq::CRTmetric>();
169 std::unique_ptr<sbnd::trigger::pmtSoftwareTrigger> pmtSoftwareTriggerMetrics = std::make_unique<sbnd::trigger::pmtSoftwareTrigger>();
173 for (
int ip=0;ip<7;++ip) { CRTMetricInfo->
hitsperplane[ip]=0; hitsperplane[ip]=0;}
174 foundBeamTrigger =
false;
176 fWvfmsVec.clear(); fWvfmsVec.resize(15*8);
177 fpmtInfoVec.clear(); fpmtInfoVec.resize(15*8);
180 std::vector<art::Handle<artdaq::Fragments>> fragmentHandles = evt.getMany<std::vector<artdaq::Fragment>>();
183 for (
auto handle : fragmentHandles) {
184 if (!handle.isValid() || handle->size() == 0)
continue;
189 if (handle->front().type() == artdaq::Fragment::ContainerFragmentType) {
191 for (
auto cont : *handle) {
192 artdaq::ContainerFragment contf(cont);
193 if (contf.fragment_type() == sbndaq::detail::FragmentType::BERNCRTV2){
194 if (fVerbose)
std::cout <<
" Found " << contf.block_count() <<
" CRT Fragments in container " << std::endl;
196 for (
size_t ii = 0; ii < contf.block_count(); ++ii) analyze_crt_fragment(*contf[ii].
get());
203 size_t beamFragmentIdx = -1;
204 for (
auto frag : *handle){
206 if (frag.type()==sbndaq::detail::FragmentType::BERNCRTV2) {
208 if (fcrt_metrics){analyze_crt_fragment(frag);}
213 if (frag.type()==sbndaq::detail::FragmentType::CAENV1730) {
220 if (!foundBeamTrigger){
221 checkCAEN1730FragmentTimeStamp(frag);
222 if (foundBeamTrigger) {
224 if (fVerbose)
std::cout <<
"Found fragment in time with beam" << std::endl;
229 if (foundBeamTrigger && beamFragmentIdx != 9999) {
230 for (
size_t fragmentIdx = beamFragmentIdx; fragmentIdx < beamFragmentIdx+8; fragmentIdx++) {
231 analyzeCAEN1730Fragment(handle->at(fragmentIdx));
242 if (fVerbose)
std::cout <<
"Found " << num_crt_frags <<
" BERNCRTV2 fragments" << std::endl;
243 if (fVerbose)
std::cout <<
"Found " << num_pmt_frags <<
" CAEN1730 fragments" << std::endl;
249 for (
int i=0;i<7;++i) {CRTMetricInfo->
hitsperplane[i] = hitsperplane[i];}
252 std::cout <<
"CRT hit count during beam spill ";
262 if (foundBeamTrigger && fWvfmsFound) {
264 pmtSoftwareTriggerMetrics->foundBeamTrigger =
true;
266 double triggerTimeStamp = fTriggerTime - beamWindowStart;
267 pmtSoftwareTriggerMetrics->triggerTimestamp = triggerTimeStamp;
268 if (fVerbose)
std::cout <<
"Saving trigger timestamp: " << triggerTimeStamp <<
" ns" << std::endl;
273 int nAboveThreshold = 0;
276 int beamStartBin = (triggerTimeStamp >= 1000)? 0 :
int(500 -
abs((triggerTimeStamp-1000)/2));
277 int beamEndBin = (triggerTimeStamp >= 1000)?
int(500 + (fBeamWindowLength*1e3 - triggerTimeStamp)/2) : (beamStartBin + (fBeamWindowLength*1e3)/2);
280 for (
int i_ch = 0; i_ch < 120; ++i_ch){
281 auto &pmtInfo = fpmtInfoVec.at(i_ch);
282 auto wvfm = fWvfmsVec[i_ch];
285 pmtInfo.channel = channelList.at(i_ch);
288 if (fBaselineAlgo ==
"constant"){ pmtInfo.baseline=fInputBaseline; pmtInfo.baselineSigma = fInputBaselineSigma; }
289 else if (fBaselineAlgo ==
"estimate") estimateBaseline(i_ch);
292 for (
int bin = beamStartBin;
bin < beamEndBin; ++
bin){
293 auto adc = wvfm[
bin];
294 if (adc < fADCThreshold){ nAboveThreshold++;
break; }
299 auto prompt_window = std::vector<uint16_t>(wvfm.begin()+500, wvfm.begin()+1000);
300 auto prelim_window = std::vector<uint16_t>(wvfm.begin()+beamStartBin, wvfm.begin()+500);
301 if (fFindPulses ==
false){
302 double ch_promptPE = (baseline-(*std::min_element(prompt_window.begin(), prompt_window.end())))/8;
303 double ch_prelimPE = (baseline-(*std::min_element(prelim_window.begin(), prelim_window.end())))/8;
304 promptPE += ch_promptPE;
305 prelimPE += ch_prelimPE;
309 if (fFindPulses ==
true){
310 SimpleThreshAlgo(i_ch);
311 for (
auto pulse : pmtInfo.pulseVec){
312 if (pulse.t_start > 500 && pulse.t_end < 550) promptPE+=pulse.pe;
313 if ((triggerTimeStamp) >= 1000){
if (pulse.t_end < 500) prelimPE+=pulse.pe; }
314 else if (triggerTimeStamp < 1000){
315 if (pulse.t_start > (500 -
abs((triggerTimeStamp-1000)/2)) && pulse.t_end < 500) prelimPE+=pulse.pe;
321 pmtSoftwareTriggerMetrics->nAboveThreshold = nAboveThreshold;
322 pmtSoftwareTriggerMetrics->promptPE = promptPE;
323 pmtSoftwareTriggerMetrics->prelimPE = prelimPE;
324 if (fVerbose)
std::cout <<
"nPMTs Above Threshold: " << nAboveThreshold << std::endl;
325 if (fVerbose)
std::cout <<
"prompt pe: " << promptPE << std::endl;
326 if (fVerbose)
std::cout <<
"prelim pe: " << prelimPE << std::endl;
329 if (fVerbose)
std::cout <<
"Beam and wvfms not found" << std::endl;
330 pmtSoftwareTriggerMetrics->foundBeamTrigger =
false;
331 pmtSoftwareTriggerMetrics->triggerTimestamp = -9999;
332 pmtSoftwareTriggerMetrics->nAboveThreshold = -9999;
333 pmtSoftwareTriggerMetrics->promptPE = -9999;
334 pmtSoftwareTriggerMetrics->prelimPE = -9999;
340 evt.put(std::move(CRTMetricInfo));
341 evt.put(std::move(pmtSoftwareTriggerMetrics));
351 sbndaq::BernCRTFragmentV2 bern_fragment(frag);
354 const sbndaq::BernCRTFragmentMetadataV2*
md = bern_fragment.metadata();
356 auto thisone = frag.fragmentID(); uint plane = (thisone & 0x0700) >> 8;
357 if (plane>7) {
std::cout <<
"bad plane value " << plane << std::endl; plane=0;}
359 for(
unsigned int iHit = 0; iHit < md->hits_in_fragment(); iHit++) {
360 sbndaq::BernCRTHitV2
const* bevt = bern_fragment.eventdata(iHit);
362 auto thisflag = bevt->flags;
363 if (thisflag & 0x2 && !(thisflag & 0xC) ) {
365 auto thistime=bevt->ts1;
366 if ((
int)thistime>fBeamWindowStart && (
int)thistime<fBeamWindowEnd) hitsperplane[plane]++;
379 sbndaq::CAENV1730Fragment bb(frag);
380 auto const*
md = bb.Metadata();
383 uint32_t timestamp =
md->timeStampNSec;
387 const uint16_t* data_begin =
reinterpret_cast<const uint16_t*
>(frag.dataBeginBytes()
388 +
sizeof(sbndaq::CAENV1730EventHeader));
389 const uint16_t* value_ptr = data_begin;
392 size_t ch_offset = (size_t)(15*fWvfmLength);
393 size_t tr_offset = fTriggerTimeOffset*1e3;
395 value_ptr = data_begin + ch_offset + tr_offset;
396 value = *(value_ptr);
398 if (value == 1 && timestamp >= beamWindowStart && timestamp <= beamWindowEnd) {
399 foundBeamTrigger =
true;
400 fTriggerTime = timestamp;
407 int fragId =
static_cast<int>(frag.fragmentID());
410 const uint16_t* data_begin =
reinterpret_cast<const uint16_t*
>(frag.dataBeginBytes()
411 +
sizeof(sbndaq::CAENV1730EventHeader));
412 const uint16_t* value_ptr = data_begin;
416 size_t nChannels = 15;
417 size_t ch_offset = 0;
420 for (
size_t i_ch = 0; i_ch < nChannels; ++i_ch){
421 fWvfmsVec[i_ch + nChannels*fragId].resize(fWvfmLength);
422 ch_offset = (size_t)(i_ch * fWvfmLength);
424 for(
size_t i_t = 0; i_t < fWvfmLength; ++i_t){
425 value_ptr = data_begin + ch_offset + i_t;
426 value = *(value_ptr);
427 fWvfmsVec[i_ch + nChannels*fragId][i_t] =
value;
433 auto wvfm = fWvfmsVec[i_ch];
434 auto &pmtInfo = fpmtInfoVec[i_ch];
436 std::vector<uint16_t> subset = std::vector<uint16_t>(wvfm.begin(), wvfm.begin()+250);
437 double subset_mean = (std::accumulate(subset.begin(), subset.end(), 0))/(subset.size());
439 for (
size_t i=0; i<subset.size();i++){ val += (subset[i] - subset_mean)*(subset[i] - subset_mean);}
440 double subset_stddev = sqrt(val/subset.size());
443 if (subset_stddev > 3){
444 val = 0; subset.clear(); subset_stddev = 0;
445 subset = std::vector<uint16_t>(wvfm.end()-500, wvfm.end());
446 subset_mean = (std::accumulate(subset.begin(), subset.end(), 0))/(subset.size());
447 for (
size_t i=0; i<subset.size();i++){ val += (subset[i] - subset_mean)*(subset[i] - subset_mean);}
448 subset_stddev = sqrt(val/subset.size());
450 pmtInfo.baseline = subset_mean;
451 pmtInfo.baselineSigma = subset_stddev;
455 auto wvfm = fWvfmsVec[i_ch];
456 auto &pmtInfo = fpmtInfoVec[i_ch];
458 double baseline_sigma = pmtInfo.baselineSigma;
464 double start_adc_thres = 5, end_adc_thres = 2;
465 double nsigma_start = 5, nsigma_end = 3;
467 auto start_threshold = ( start_adc_thres > (nsigma_start * baseline_sigma) ? (baseline-start_adc_thres) : (baseline-(nsigma_start * baseline_sigma)));
468 auto end_threshold = ( end_adc_thres > (nsigma_end * baseline_sigma) ? (baseline - end_adc_thres) : (baseline - (nsigma_end * baseline_sigma)));
470 std::vector<sbnd::trigger::pmtPulse> pulse_vec;
473 for (
auto const &adc : wvfm){
474 if ( !fire && ((
double)adc) <= start_threshold ){
480 if( fire && ((
double)adc) > end_threshold ){
483 pulse.
t_end = counter < ((int)wvfm.size()) ? counter : counter - 1;
484 pulse_vec.push_back(pulse);
489 pulse.
area += (baseline-(double)adc);
490 if (pulse.
peak > (baseline-(
double)adc)) {
491 pulse.
peak = (baseline-(double)adc);
500 pulse.
t_end = counter - 1;
501 pulse_vec.push_back(pulse);
505 pmtInfo.pulseVec = pulse_vec;
507 for (
auto &pulse : pmtInfo.pulseVec){pulse.
pe = pulse.
area/fPEArea;}
double fTriggerTimeOffset
std::vector< unsigned int > channelList
void analyze_crt_fragment(artdaq::Fragment &frag)
MetricProducer(fhicl::ParameterSet const &p)
MetricProducer & operator=(MetricProducer const &)=delete
std::vector< sbnd::trigger::pmtInfo > fpmtInfoVec
void produce(art::Event &evt) override
void estimateBaseline(int i_ch)
double fInputBaselineSigma
std::string fBaselineAlgo
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
art::Persistable is_persistable_
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
void analyzeCAEN1730Fragment(const artdaq::Fragment &frag)
void checkCAEN1730FragmentTimeStamp(const artdaq::Fragment &frag)
opdet::sbndPDMapAlg pdMap
void SimpleThreshAlgo(int i_ch)
art::EventNumber_t fEvent
std::vector< std::vector< uint16_t > > fWvfmsVec
BEGIN_PROLOG could also be cout