26 #include "art/Framework/Core/ReplicatedProducer.h"
27 #include "art/Framework/Principal/Event.h"
28 #include "art/Framework/Services/Registry/ServiceHandle.h"
29 #include "art_root_io/TFileService.h"
30 #include "art/Framework/Core/ModuleMacros.h"
31 #include "art/Utilities/Globals.h"
32 #include "art/Utilities/make_tool.h"
33 #include "canvas/Persistency/Common/Ptr.h"
34 #include "messagefacility/MessageLogger/MessageLogger.h"
35 #include "cetlib/cpu_timer.h"
37 #include "tbb/parallel_for.h"
38 #include "tbb/blocked_range.h"
39 #include "tbb/task_arena.h"
40 #include "tbb/spin_mutex.h"
41 #include "tbb/concurrent_vector.h"
49 #include "sbndaq-artdaq-core/Overlays/ICARUS/PhysCrateFragment.hh"
55 #include "icarus_signal_processing/ICARUSSigProcDefs.h"
56 #include "icarus_signal_processing/WaveformTools.h"
57 #include "icarus_signal_processing/Filters/FFTFilterFunctions.h"
58 #include "icarus_signal_processing/Filters/ImageFilters.h"
59 #include "icarus_signal_processing/Denoising.h"
60 #include "icarus_signal_processing/Detection/EdgeDetection.h"
61 #include "icarus_signal_processing/Filters/BilateralFilters.h"
62 #include "icarus_signal_processing/ROIFinder2D.h"
76 virtual void configure(fhicl::ParameterSet
const & pset);
77 virtual void produce(art::Event &
e, art::ProcessingFrame
const& frame);
78 virtual void beginJob(art::ProcessingFrame
const& frame);
79 virtual void endJob(art::ProcessingFrame
const& frame);
101 using ChannelArrayPair = std::pair<daq::INoiseFilter::ChannelPlaneVec,icarus_signal_processing::ArrayFloat>;
108 art::Handle<artdaq::Fragments>,
120 art::Handle<artdaq::Fragments>
const& fragmentsHandle,
134 void operator()(
const tbb::blocked_range<size_t>& range)
const
136 for (
size_t idx = range.begin(); idx < range.end(); idx++)
150 void saveRawDigits(
const icarus_signal_processing::ArrayFloat&,
151 const icarus_signal_processing::VectorFloat&,
152 const icarus_signal_processing::VectorFloat&,
153 const icarus_signal_processing::VectorInt&,
204 art::ReplicatedProducer(pset, frame),
207 fGeometry = art::ServiceHandle<geo::Geometry const>{}.get();
208 fChannelMap = art::ServiceHandle<icarusDB::IICARUSChannelMap const>{}.get();
215 mf::LogDebug(
"DaqDecoderICARUSTPCwROI") <<
" ==> concurrency: " << max_concurrency << std::endl;
218 const fhicl::ParameterSet& decoderToolParams = pset.get<fhicl::ParameterSet>(
"DecoderTool");
220 fDecoderToolVec.resize(max_concurrency);
222 for(
auto& decoderTool : fDecoderToolVec)
225 decoderTool = art::make_tool<INoiseFilter>(decoderToolParams);
231 for(
const auto& fragmentLabel : fFragmentsLabelVec)
233 produces<std::vector<raw::RawDigit>>(fragmentLabel.instance());
234 produces<std::vector<recob::ChannelROI>>(fragmentLabel.instance());
236 if (fOutputRawWaveform)
237 produces<std::vector<raw::RawDigit>>(fragmentLabel.instance() + fOutputRawWavePath);
239 if (fOutputCorrection)
240 produces<std::vector<raw::RawDigit>>(fragmentLabel.instance() + fOutputCoherentPath);
246 for(
size_t cryoIdx = 0; cryoIdx < 2; cryoIdx++)
248 for(
size_t logicalTPCIdx = 0; logicalTPCIdx < 4; logicalTPCIdx++)
250 for(
size_t planeIdx = 0; planeIdx < 3; planeIdx++)
258 fPlaneToROPPlaneMap[planeID] = ropID.
ROP;
259 fPlaneToWireOffsetMap[planeID] = channel;
260 planeToLastWireOffsetMap[planeID] = fGeometry->PlaneWireToChannel(planeID.
Plane, fGeometry->Nwires(planeID), planeID.
TPC, planeID.
Cryostat);
261 fROPToNumWiresMap[ropID.
ROP] = fGeometry->Nwires(planeID);
263 if (ropID.
ROP > fNumROPs) fNumROPs = ropID.
ROP;
266 if (ropID.
ROP > 1 && (logicalTPCIdx == 1 || logicalTPCIdx == 3))
270 fPlaneToWireOffsetMap[planeID] = fPlaneToWireOffsetMap[tempID];
271 fROPToNumWiresMap[ropID.
ROP] = planeToLastWireOffsetMap[planeID] - fPlaneToWireOffsetMap[planeID];
275 mf::LogDebug(
fLogCategory) <<
"Initializing C/T/P: " << planeID.
Cryostat <<
"/" << planeID.
TPC <<
"/" << planeID.
Plane <<
", base channel: " << fPlaneToWireOffsetMap[planeID] <<
", ROP: " << ropID <<
", index: " << ropID.
ROP;
284 mf::LogInfo(
"DaqDecoderICARUSTPCwROI") <<
"DaqDecoderICARUSTPCwROI configured\n";
301 fFragmentsLabelVec = pset.get<std::vector<art::InputTag>>(
"FragmentsLabelVec", std::vector<art::InputTag>()={
"daq:PHYSCRATEDATA"});
332 mf::LogDebug(
"DaqDecoderICARUSTPCwROI") <<
"**** Processing raw data fragments ****" << std::endl;
338 int max_concurrency = tbb::this_task_arena::max_concurrency();
340 mf::LogDebug(
"DaqDecoderICARUSTPCwROI") <<
" ==> concurrency: " << max_concurrency << std::endl;
342 cet::cpu_timer theClockTotal;
344 theClockTotal.start();
351 art::Handle<artdaq::Fragments>
const& daq_handle
352 = dataCacheRemover.
getHandle<artdaq::Fragments>(fragmentLabel);
365 for(
size_t ropIdx = 0; ropIdx <
fNumROPs; ropIdx++)
370 channelArrayPair.second.resize(
fROPToNumWiresMap[ropIdx],icarus_signal_processing::VectorFloat(4096));
372 mf::LogDebug(
"DaqDecoderICARUSTPCwROI") <<
"**> Initializing ropIdx: " << ropIdx <<
" channelPairVec to " << channelArrayPair.first.size() <<
" channels with " << channelArrayPair.second[0].size() <<
" ticks" << std::endl;
375 mf::LogDebug(
"DaqDecoderICARUSTPCwROI") <<
"****> Let's get ready to rumble!" << std::endl;
378 auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService>()->DataFor(event);
380 multiThreadFragmentProcessing fragmentProcessing(*
this, clockData, daq_handle, concurrentRawRawDigits, concurrentRawDigits, coherentRawDigits, concurrentROIs);
382 tbb::parallel_for(tbb::blocked_range<size_t>(0, daq_handle->size()), fragmentProcessing);
390 RawDigitCollectionPtr rawDigitCollection = std::make_unique<std::vector<raw::RawDigit>>(std::move_iterator(concurrentRawDigits.begin()),
391 std::move_iterator(concurrentRawDigits.end()));
394 std::sort(rawDigitCollection->begin(),rawDigitCollection->end(),[](
const auto&
left,
const auto&
right){
return left.Channel() <
right.Channel();});
397 mf::LogDebug(
"DaqDecoderICARUSTPCwROI") <<
"****> Total size of map: " << planeIdxToImageMap.size() << std::endl;
398 for(
const auto& planeImagePair : planeIdxToImageMap)
400 mf::LogDebug(
"DaqDecoderICARUSTPCwROI") <<
" - plane: " << planeImagePair.first <<
" has " << planeImagePair.second.size() <<
" wires" << std::endl;
404 event.put(std::move(rawDigitCollection), fragmentLabel.instance());
407 ChannelROICollectionPtr channelROICollection = std::make_unique<std::vector<recob::ChannelROI>>(std::move_iterator(concurrentROIs.begin()),
408 std::move_iterator(concurrentROIs.end()));
410 std::sort(channelROICollection->begin(),channelROICollection->end(),[](
const auto&
left,
const auto&
right){
return left.Channel() <
right.Channel();});
412 event.put(std::move(channelROICollection), fragmentLabel.instance());
418 RawDigitCollectionPtr rawRawDigitCollection = std::make_unique<std::vector<raw::RawDigit>>(std::move_iterator(concurrentRawRawDigits.begin()),
419 std::move_iterator(concurrentRawRawDigits.end()));
422 std::sort(rawRawDigitCollection->begin(),rawRawDigitCollection->end(),[](
const auto&
left,
const auto&
right){
return left.Channel() <
right.Channel();});
425 event.put(std::move(rawRawDigitCollection),fragmentLabel.instance() +
fOutputRawWavePath);
431 RawDigitCollectionPtr coherentCollection = std::make_unique<std::vector<raw::RawDigit>>(std::move_iterator(coherentRawDigits.begin()),
432 std::move_iterator(coherentRawDigits.end()));
435 std::sort(coherentCollection->begin(),coherentCollection->end(),[](
const auto&
left,
const auto&
right){
return left.Channel() <
right.Channel();});
442 theClockTotal.stop();
444 double totalTime = theClockTotal.accumulated_real_time();
446 mf::LogInfo(
fLogCategory) <<
"==> DaqDecoderICARUSTPCwROI total time: " << totalTime << std::endl;
453 art::Handle<artdaq::Fragments> fragmentHandle,
459 cet::cpu_timer theClockProcess;
461 theClockProcess.start();
463 art::Ptr<artdaq::Fragment> fragmentPtr(fragmentHandle, idx);
465 mf::LogDebug(
"DaqDecoderICARUSTPCwROI") <<
"--> Processing fragment ID: " << fragmentPtr->fragmentID() << std::endl;
466 mf::LogDebug(
"DaqDecoderICARUSTPCwROI") <<
" ==> Current thread index: " << tbb::this_task_arena::current_thread_index() << std::endl;
468 cet::cpu_timer theClockTotal;
470 theClockTotal.start();
473 icarus::PhysCrateFragment physCrateFragment(*fragmentPtr);
475 size_t nBoardsPerFragment = physCrateFragment.nBoards();
476 size_t nChannelsPerBoard = physCrateFragment.nChannelsPerBoard();
477 size_t nSamplesPerChannel = physCrateFragment.nSamplesPerChannel();
481 artdaq::detail::RawFragmentHeader::fragment_id_t fragmentID = fragmentPtr->fragmentID();
483 mf::LogDebug(
fLogCategory) <<
"==> Recovered fragmentID: " << std::hex << fragmentID << std::dec << std::endl;
500 for(
const auto& boardID : readoutIDVec)
505 mf::LogDebug(
fLogCategory) <<
"*** COULD NOT FIND BOARD ***\n" <<
506 " - boardID: " << std::hex << boardID <<
", board map size: " << readoutIDVec.size() <<
", nBoardsPerFragment: " << nBoardsPerFragment;
513 boardIDVec[boardSlot] = boardID;
516 std::string boardIDs =
"";
518 for(
const auto&
id : boardIDVec) boardIDs +=
std::to_string(
id) +
" ";
520 mf::LogDebug(
fLogCategory) <<
" - # boards: " << boardIDVec.size() <<
", boards: " << boardIDs;
522 cet::cpu_timer theClockPedestal;
524 theClockPedestal.start();
532 channelArrayPair.first.resize(nChannelsPerBoard);
533 channelArrayPair.second.resize(nChannelsPerBoard,icarus_signal_processing::VectorFloat(nSamplesPerChannel));
540 for(
size_t board = 0; board < boardIDVec.size(); board++)
543 if (board >= nBoardsPerFragment)
545 mf::LogInfo(
"TPCDecoderFilter1D") <<
" Asking for board beyond number in fragment, want board " << board <<
", maximum is " << nBoardsPerFragment << std::endl;
549 uint32_t boardSlot = physCrateFragment.DataTileHeader(board)->StatusReg_SlotID();
553 mf::LogDebug(
fLogCategory) <<
"********************************************************************************\n"
554 <<
"FragmentID: " << std::hex << fragmentID << std::dec <<
", Crate: " << crateName <<
", boardID: " << boardSlot <<
"/" << nBoardsPerFragment <<
", size " << channelPlanePairVec.size() <<
"/" << nChannelsPerBoard;
556 if (board != boardSlot)
558 mf::LogInfo(
fLogCategory) <<
"==> Found board/boardSlot mismatch, crate: " << crateName <<
", board: " << board <<
", boardSlot: " << boardSlot <<
" channelPlanePair: " <<
fChannelMap->
getChannelPlanePair(boardIDVec[board]).front().first <<
"/" <<
fChannelMap->
getChannelPlanePair(boardIDVec[board]).front().second <<
", slot: " << channelPlanePairVec[0].first <<
"/" << channelPlanePairVec[0].second;
562 const icarus::A2795DataBlock::data_t* dataBlock = physCrateFragment.BoardData(board);
565 for(
size_t chanIdx = 0; chanIdx < nChannelsPerBoard; chanIdx++)
567 icarus_signal_processing::VectorFloat& rawDataVec = channelArrayPair.second[chanIdx];
570 rawDataVec[
tick] = -dataBlock[chanIdx +
tick * nChannelsPerBoard];
573 channelArrayPair.first[chanIdx] = channelPlanePairVec[chanIdx];
580 icarus_signal_processing::WaveformTools<float> waveformTools;
583 float localPedestal(0.);
584 float localFullRMS(0.);
585 float localTruncRMS(0.);
586 int localNumTruncBins(0);
587 int localRangeBins(0);
594 icarus_signal_processing::VectorFloat pedCorWaveforms(denoised[0].
size());
596 for(
size_t chanIdx = 0; chanIdx < nChannelsPerBoard; chanIdx++)
604 const icarus_signal_processing::VectorFloat& waveform = decoderTool->
getPedCorWaveforms()[chanIdx];
607 std::transform(waveform.begin(),waveform.end(),wvfm.begin(),[](
const auto& val){
return short(std::round(val));});
609 ConcurrentRawDigitCol::iterator newRawObjItr = concurrentRawRawDigitCol.emplace_back(channel,wvfm.size(),wvfm);
616 const icarus_signal_processing::VectorFloat& corrections = decoderTool->
getCorrectedMedians()[chanIdx];
619 std::transform(corrections.begin(),corrections.end(),wvfm.begin(),[](
const auto& val){
return short(std::round(val));});
622 ConcurrentRawDigitCol::iterator newRawObjItr = coherentRawDigitCol.push_back(
raw::RawDigit(channel,wvfm.size(),wvfm));
624 newRawObjItr->SetPedestal(0.,0.);
628 waveformTools.getPedestalCorrectedWaveform(denoised[chanIdx],
639 std::transform(pedCorWaveforms.begin(),pedCorWaveforms.end(),wvfm.begin(),[](
const auto& val){
return short(std::round(val));});
641 ConcurrentRawDigitCol::iterator newObjItr = concurrentRawDigitCol.emplace_back(channel,wvfm.size(),wvfm);
643 newObjItr->SetPedestal(localPedestal,localFullRMS);
646 const icarus_signal_processing::VectorBool& chanROIs = decoderTool->
getROIVals()[chanIdx];
652 while(roiIdx < chanROIs.size())
654 size_t roiStartIdx = roiIdx;
656 while(roiIdx < chanROIs.size() && chanROIs[roiIdx]) roiIdx++;
658 if (roiIdx > roiStartIdx)
660 std::vector<short> holder(roiIdx - roiStartIdx);
662 for(
size_t idx = 0; idx < holder.size(); idx++) holder[idx] = wvfm[roiStartIdx+idx];
664 ROIVec.
add_range(roiStartIdx, std::move(holder));
681 theClockProcess.stop();
683 double totalTime = theClockProcess.accumulated_real_time();
685 mf::LogDebug(
fLogCategory) <<
"--> Exiting fragment processing for thread: " << tbb::this_task_arena::current_thread_index() <<
", time: " << totalTime << std::endl;
virtual const icarus_signal_processing::ArrayFloat & getWaveLessCoherent() const =0
Recover the waveforms less coherent noise.
std::unique_ptr< RawDigitCollection > RawDigitCollectionPtr
std::pair< daq::INoiseFilter::ChannelPlaneVec, icarus_signal_processing::ArrayFloat > ChannelArrayPair
multiThreadFragmentProcessing(DaqDecoderICARUSTPCwROI const &parent, detinfo::DetectorClocksData const &clockData, art::Handle< artdaq::Fragments > const &fragmentsHandle, ConcurrentRawDigitCol &concurrentRawRawDigits, ConcurrentRawDigitCol &concurrentRawDigits, ConcurrentRawDigitCol &coherentRawDigits, ConcurrentChannelROICol &concurrentROIs)
ConcurrentRawDigitCol & fConcurrentRawRawDigits
std::vector< ChannelPlanePair > ChannelPlanePairVec
std::vector< raw::RawDigit > RawDigitCollection
Collection of charge vs time digitized from a single readout channel.
virtual ~DaqDecoderICARUSTPCwROI()
Destructor.
void saveRawDigits(const icarus_signal_processing::ArrayFloat &, const icarus_signal_processing::VectorFloat &, const icarus_signal_processing::VectorFloat &, const icarus_signal_processing::VectorInt &, ConcurrentRawDigitCol &) const
std::map< unsigned int, icarus_signal_processing::ArrayFloat > PlaneIdxToImageMap
art::Handle< artdaq::Fragments > const & fFragmentsHandle
tbb::concurrent_vector< raw::RawDigit > ConcurrentRawDigitCol
std::vector< unsigned int > ReadoutIDVec
virtual const ReadoutIDVec & getReadoutBoardVec(const unsigned int) const =0
std::vector< std::unique_ptr< INoiseFilter > > fDecoderToolVec
Decoder tools.
This provides an art tool interface definition for tools which "decode" artdaq fragments into LArSoft...
std::vector< ChannelArrayPair > ChannelArrayPairVec
The data type to uniquely identify a Plane.
virtual const icarus_signal_processing::ArrayFloat & getPedCorWaveforms() const =0
Recover the pedestal corrected waveforms.
std::vector< short > ADCvector_t
Type representing a (compressed) vector of ADC counts.
const std::string instance
const datarange_t & add_range(size_type offset, ITER first, ITER last)
Adds a sequence of elements as a range with specified offset.
CryostatID_t Cryostat
Index of cryostat.
Definition of basic raw digits.
std::size_t size(FixedBins< T, C > const &) noexcept
bool fOutputCorrection
Should we output the coherent noise correction vectors?
std::unique_ptr< ChannelROICollection > ChannelROICollectionPtr
virtual const icarus_signal_processing::ArrayBool & getROIVals() const =0
Recover the ROI values.
virtual void process_fragment(detinfo::DetectorClocksData const &, const daq::INoiseFilter::ChannelPlaneVec &, const icarus_signal_processing::ArrayFloat &, const size_t &)=0
std::vector< raw::ChannelID_t > ChannelVec
bool fDiagnosticOutput
Set this to get lots of messages.
virtual void configure(fhicl::ParameterSet const &pset)
geo::GeometryCore const * fGeometry
pointer to Geometry service
virtual void endJob(art::ProcessingFrame const &frame)
End job method.
virtual const std::string & getCrateName(const unsigned int) const =0
ConcurrentRawDigitCol & fConcurrentRawDigits
int fNumEvent
Number of events seen.
virtual bool hasBoardID(const unsigned int) const =0
ROPID_t ROP
Index of the readout plane within its TPC set.
ROPToNumWiresMap fROPToNumWiresMap
bool fDropRawDataAfterUse
Clear fragment data product cache after use.
icarus_signal_processing::VectorFloat fThresholdVec
"threshold vector" filled during decoding loop
std::map< geo::PlaneID, unsigned int > PlaneToROPPlaneMap
float fSigmaForTruncation
Cut for truncated rms calc.
virtual const ChannelPlanePairVec & getChannelPlanePair(const unsigned int) const =0
const DaqDecoderICARUSTPCwROI & fDaqDecoderICARUSTPCwROI
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
std::vector< art::InputTag > fFragmentsLabelVec
The input artdaq fragment label vector (for more than one)
virtual bool hasFragmentID(const unsigned int) const =0
virtual const icarus_signal_processing::ArrayFloat & getCorrectedMedians() const =0
Recover the correction median values.
const icarusDB::IICARUSChannelMap * fChannelMap
PlaneID_t Plane
Index of the plane within its TPC.
PlaneToROPPlaneMap fPlaneToROPPlaneMap
std::map< geo::PlaneID, raw::ChannelID_t > PlaneToWireOffsetMap
std::map< unsigned int, unsigned int > ROPToNumWiresMap
Description of geometry of one entire detector.
IDecoderFilter interface class definiton.
Class identifying a set of planes sharing readout channels.
std::pair< unsigned int, icarus_signal_processing::ArrayFloat > PlaneIdxToImagePair
virtual const icarus_signal_processing::VectorFloat & getPedestalVals() const =0
Recover the pedestals for each channel.
Helper functions to create a wire.
void operator()(const tbb::blocked_range< size_t > &range) const
ConcurrentRawDigitCol & fCoherentRawDigits
std::vector< recob::ChannelROI > ChannelROICollection
std::pair< unsigned int, ChannelVec > PlaneIdxToChannelPair
Contains all timing reference information for the detector.
std::string to_string(WindowPattern const &pattern)
Class managing the creation of a new recob::Wire object.
tbb::concurrent_vector< recob::ChannelROI > ConcurrentChannelROICol
Declaration of basic channel signal object for ICARUS.
void processSingleFragment(size_t, detinfo::DetectorClocksData const &clockData, art::Handle< artdaq::Fragments >, ConcurrentRawDigitCol &, ConcurrentRawDigitCol &, ConcurrentRawDigitCol &, ConcurrentChannelROICol &) const
std::map< unsigned int, ChannelVec > PlaneIdxToChannelMap
std::string fOutputCoherentPath
Path to assign to the output if asked for.
detinfo::DetectorClocksData const & fClockData
virtual void produce(art::Event &e, art::ProcessingFrame const &frame)
virtual unsigned int getBoardSlot(const unsigned int) const =0
virtual void beginJob(art::ProcessingFrame const &frame)
Begin job method.
virtual const icarus_signal_processing::VectorFloat & getFullRMSVals() const =0
Recover the full RMS before coherent noise.
DaqDecoderICARUSTPCwROI(fhicl::ParameterSet const &pset, art::ProcessingFrame const &frame)
bool fOutputRawWaveform
Should we output pedestal corrected (not noise filtered)?
unsigned int ChannelID_t
Type representing the ID of a readout channel.
art::Handle< T > getHandle(Args &&...args)
Retrieves an handle from the event, and registers it.
size_t fCoherentNoiseGrouping
Grouping for removing coherent noise.
PlaneToWireOffsetMap fPlaneToWireOffsetMap
TPCID_t TPC
Index of the TPC within its cryostat.
Tracks handles for cache deletion.
const std::string fLogCategory
Output category when logging messages.
std::string fOutputRawWavePath
Path to assign to the output if asked for.
Variant of util::ArtHandleTrackerManager in local scope.
art framework interface to geometry description
ConcurrentChannelROICol & fConcurrentROIs