34 #include "art/Framework/Core/ModuleMacros.h"
35 #include "art/Framework/Core/EDProducer.h"
36 #include "art/Framework/Principal/Event.h"
37 #include "art/Framework/Principal/Run.h"
38 #include "art/Framework/Principal/Handle.h"
39 #include "art/Persistency/Common/PtrMaker.h"
40 #include "art/Utilities/make_tool.h"
41 #include "canvas/Persistency/Common/Assns.h"
42 #include "canvas/Persistency/Common/Ptr.h"
43 #include "canvas/Utilities/InputTag.h"
44 #include "cetlib_except/exception.h"
45 #include "messagefacility/MessageLogger/MessageLogger.h"
46 #include "fhiclcpp/types/OptionalSequence.h"
47 #include "fhiclcpp/types/OptionalAtom.h"
48 #include "fhiclcpp/types/Table.h"
49 #include "fhiclcpp/types/TableAs.h"
50 #include "fhiclcpp/types/Sequence.h"
51 #include "fhiclcpp/types/Atom.h"
52 #include "fhiclcpp/types/DelegatedParameter.h"
53 #include "fhiclcpp/ParameterSet.h"
63 namespace icarus::trigger {
class DiscriminatePMTwaveformsByChannel; }
221 Comment(
"the baseline for this channel [ADC]")
226 Comment(
"threshold relative to the baseline for this channel [ADC]")
237 Name(
"OpticalWaveforms"),
238 Comment(
"label of input digitized optical waveform data product"),
244 Comment(
"label of input waveform baselines (parallel to the waveforms)")
249 Comment(
"constant baseline for all waveforms, in ADC counts")
253 Name(
"TriggerGateBuilder"),
255 (
"parameters for generating trigger gates from optical channel output")
259 Name(
"DefaultThreshold"),
260 Comment(
"threshold for all channels up to NChannel [ADC]")
264 Name(
"ThresholdList"),
265 Comment(
"relative thresholds for each channel from #0 on [ADC]"),
266 std::vector<raw::ADC_Count_t>{}
270 Name(
"ThresholdsFromPMTconfig"),
271 Comment(
"read thresholds from this PMT configuration run by run")
274 fhicl::Sequence<fhicl::TableAs<ChannelInfo_t, ChannelConfig>>
Thresholds {
277 (
"thresholds for the specified channels; overrides `ThresholdList`"),
278 std::vector<ChannelInfo_t>{}
284 Comment(
"minimum number of channels to provide (default: all)")
288 Name(
"SavePMTcoverage"),
289 Comment(
"write also a sbn::OpDetWaveformMeta collection"),
294 Name(
"OutputInstanceName"),
295 Comment(
"instance name for the output products (none by default)"),
300 Name(
"OutputCategory"),
301 Comment(
"tag of the module output to console via message facility"),
302 "DiscriminatePMTwaveformsByChannel"
321 virtual void beginRun(art::Run& run)
override;
324 virtual void produce(art::Event& event)
override;
405 template <
typename Logger = mf::LogInfo>
429 (fhicl::OptionalAtom<unsigned int>
const& param);
432 (std::vector<ChannelInfo_t>
const& config);
442 bool icarus::trigger::DiscriminatePMTwaveformsByChannel::ChannelInfo_t::operator==
445 return (channel == other.channel)
447 && (threshold == other.threshold)
453 namespace icarus::trigger {
468 bool icarus::trigger::DiscriminatePMTwaveformsByChannel::ChannelInfo_t::operator<
470 {
return channel < other.channel; }
478 : art::EDProducer(config)
483 , fNOpDetChannels(getNOpDetChannels(config().
NChannels))
485 , fThresholdList(config().ThresholdList())
486 , fThresholdsFromPMTconfig
488 , fChannelInfos(readChannelInfoSpecs(config().
Thresholds()))
489 , fOutputInstanceName(config().OutputInstanceName())
490 , fSavePMTcoverage(config().SavePMTcoverage())
492 , fTriggerGateBuilder
494 art::make_tool<icarus::trigger::TriggerGateBuilder>
495 (config().TriggerGateBuilder_.get<fhicl::ParameterSet>())
499 if (config().DefaultThreshold.hasValue()
500 || config().ThresholdsFromPMTconfig.hasValue()
502 if (!config().NChannels.hasValue()) {
503 throw art::Exception(art::errors::Configuration)
504 <<
"Configuration parameter `" << config().NChannels.name()
505 <<
"` not specified: it is mandatory when either `"
506 << config().DefaultThreshold.name() <<
"` or `"
507 << config().ThresholdsFromPMTconfig.name() <<
"` are specified.\n";
514 if (
bool(
fBaseline) +
bool(fBaselineTag) != 1)
516 throw art::Exception(art::errors::Configuration)
517 <<
"Exactly one among options `" << config().Baselines.name() <<
"` ("
518 << (fBaselineTag? (
"'" + fBaselineTag->encode() +
"'"):
"not set")
519 <<
") and `" << config().Baseline.name() <<
"` ("
521 <<
") must be specified.\n";
525 refreshCurrentThresholds();
526 refreshCurrentBaselines();
527 if (!fThresholdsFromPMTconfig) printCurrentThresholdsAndBaselines();
532 consumes<std::vector<raw::OpDetWaveform>>(fOpDetWaveformTag);
534 if (fThresholdsFromPMTconfig)
535 consumes<sbn::PMTconfiguration, art::InRun>(*fThresholdsFromPMTconfig);
542 produces<std::vector<TriggerGateData_t>>(fOutputInstanceName);
543 produces<art::Assns<TriggerGateData_t, raw::OpDetWaveform>>
544 (fOutputInstanceName);
545 if (fSavePMTcoverage) {
546 produces<std::vector<sbn::OpDetWaveformMeta>>(fOutputInstanceName);
547 produces<art::Assns<raw::OpDetWaveform, sbn::OpDetWaveformMeta>>
548 (fOutputInstanceName);
549 produces<art::Assns<sbn::OpDetWaveformMeta, TriggerGateData_t>>
550 (fOutputInstanceName);
560 if (fThresholdsFromPMTconfig) {
564 if (!fPMTconfig || (fPMTconfig !=
PMTconfig)) {
566 refreshCurrentThresholds();
567 printCurrentThresholdsAndBaselines();
581 art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(event)
587 auto const& waveformHandle
589 auto const& waveforms = *waveformHandle;
592 auto const& opDetWavePtrs
598 std::vector<icarus::WaveformBaseline> baselines;
602 baselines =
event.getProduct<std::vector<icarus::WaveformBaseline>>
608 baselines.reserve(waveforms.size());
609 for (
auto const& waveform: waveforms) {
610 auto const channelSlot
611 =
static_cast<std::size_t
>(waveform.ChannelNumber());
613 throw cet::exception(
"DiscriminatePMTwaveformsByChannel")
614 <<
"Waveforms on channel " << waveform.ChannelNumber()
615 <<
" have no baseline configured.\n";
623 log <<
"Discrimination of " << waveforms.size() <<
" PMT waveforms from '"
626 log <<
" with baselines from '" <<
fBaselineTag->encode() <<
"'";
642 std::vector<std::vector<icarus::trigger::WaveformWithBaseline>>
647 auto const channelSlot =
static_cast<std::size_t
>(waveform.ChannelNumber());
648 if (channelSlot >= waveformInfoPerChannel.size())
continue;
650 waveformInfoPerChannel[channelSlot].emplace_back
657 for (
auto const& [ channelSlot, waveInfo ]:
661 if (waveInfo.empty()) {
669 if (threshold.isUnset()) {
670 throw cet::exception(
"DiscriminatePMTwaveformsByChannel")
671 <<
"No threshold set up for PMT channel #" << channel <<
".\n";
677 <<
"Processing PMT channel #" << channel
678 <<
" (first waveform baseline: " << waveInfo.front().baseline()
689 assert(channelGates.size() == 1);
690 gates.push_back(std::move(channelGates.front()));
696 log <<
"Trigger gates:\n";
697 unsigned int nOpenGates = gates.size();
698 for (
auto const& gate: gates)
if (gate.gate().alwaysClosed()) --nOpenGates;
699 log << nOpenGates <<
"/" << gates.size() <<
" trigger gates";
702 for (
auto const& gate: gates) {
703 if (gate.gate().alwaysClosed())
continue;
704 log <<
"\n " << gate;
712 art::PtrMaker<TriggerGateData_t>
const makeGatePtr
719 (std::move(gates), makeGatePtr, opDetWavePtrs);
723 art::PtrMaker<sbn::OpDetWaveformMeta>
const makePMTinfoPtr
729 std::vector<sbn::OpDetWaveformMeta> PMTinfo;
730 art::Assns<raw::OpDetWaveform, sbn::OpDetWaveformMeta> WavePMTinfoAssns;
731 art::PtrMaker<raw::OpDetWaveform>
const makeWavePtr
732 { event, waveformHandle.id() };
734 for (
auto const& [ iWaveform, waveform ]:
util::enumerate(waveforms)) {
736 PMTinfo.push_back(makePMTinfo(waveform));
738 WavePMTinfoAssns.addSingle
739 (makeWavePtr(iWaveform), makePMTinfoPtr(iWaveform));
745 art::Assns<sbn::OpDetWaveformMeta, TriggerGateData_t> PMTinfoGateAssns;
746 for (
auto [ gatePtr, wavePtr ]: assns)
747 PMTinfoGateAssns.addSingle(makePMTinfoPtr(wavePtr.key()), gatePtr);
750 std::make_unique<std::vector<sbn::OpDetWaveformMeta>>(std::move(PMTinfo)),
754 std::make_unique<art::Assns<raw::OpDetWaveform, sbn::OpDetWaveformMeta>>
755 (std::move(WavePMTinfoAssns)),
759 std::make_unique<art::Assns<sbn::OpDetWaveformMeta, TriggerGateData_t>>
760 (std::move(PMTinfoGateAssns)),
770 std::make_unique<std::vector<TriggerGateData_t>>(std::move(data)),
774 std::make_unique<art::Assns<TriggerGateData_t, raw::OpDetWaveform>>
789 fCurrentThresholds.clear();
794 if (fNOpDetChannels > 0U) {
795 fCurrentThresholds.resize(
797 fDefaultThreshold.has_value()
807 if (fCurrentThresholds.size() < fThresholdList.size())
808 fCurrentThresholds.resize(fThresholdList.size());
822 auto const channelSlot
823 =
static_cast<std::size_t
>(channelConfig.
channelID);
824 if (fCurrentThresholds.size() <= channelSlot)
825 fCurrentThresholds.resize(channelSlot + 1U);
827 fCurrentThresholds[channelSlot] = {
839 for (
auto const& chInfo: fChannelInfos) {
840 if (!chInfo.threshold.has_value())
continue;
841 auto const channelSlot =
static_cast<std::size_t
>(chInfo.channel);
842 if (fCurrentThresholds.size() <= channelSlot)
843 fCurrentThresholds.resize(channelSlot + 1U);
844 fCurrentThresholds[channelSlot] = {
859 fCurrentBaselines.clear();
864 if ((fNOpDetChannels > 0U) &&
fBaseline.has_value()) {
865 fCurrentBaselines.resize(
875 for (
auto const& chInfo: fChannelInfos) {
876 if (!chInfo.baseline.has_value())
continue;
877 auto const channelSlot =
static_cast<std::size_t
>(chInfo.channel);
878 if (fCurrentBaselines.size() <= channelSlot)
879 fCurrentBaselines.resize(channelSlot + 1U);
880 fCurrentBaselines[channelSlot] = {
890 template <
typename Logger >
902 case Source_t::List: log <<
"(from threshold list)";
908 case Source_t::Run: log <<
"(from run information)";
910 case Source_t::Event: log <<
"(from event information)";
912 case Source_t::ChannelSpec: log <<
"(specified for this channel)";
917 std::size_t
const nChannels
918 = std::max(fCurrentThresholds.size(), fCurrentBaselines.size());
919 log <<
"discrimination settings for " << nChannels <<
" channels";
920 if ((fNOpDetChannels > 0U) && (fNOpDetChannels < nChannels))
921 log <<
" (but only the first " << fNOpDetChannels <<
" will be processed)";
925 log <<
"\n channel " << channel
927 if (channel < fCurrentThresholds.size()) {
928 auto const& thrInfo = fCurrentThresholds[channel];
930 printSourceTag(thrInfo.source);
934 log <<
"; baseline ";
935 if (channel < fCurrentBaselines.size()) {
936 auto const& blineInfo = fCurrentBaselines[channel];
937 if (blineInfo.source !=
Source_t::Unset) log << blineInfo.value <<
' ';
938 printSourceTag(blineInfo.source);
949 (fhicl::OptionalAtom<unsigned int>
const& param)
951 unsigned int nChannels;
953 param(nChannels)? nChannels: lar::providerFrom<geo::Geometry>()->
NOpDets();
959 (std::vector<ChannelInfo_t>
const& config) -> std::vector<ChannelInfo_t>
961 std::vector<ChannelInfo_t> chMap = config;
963 auto const compareByChannel
965 {
return a.
channel == b.channel; }
969 std::sort(chMap.begin(), chMap.end());
970 auto iDup = std::unique(chMap.begin(), chMap.end(), compareByChannel);
971 if (iDup != chMap.end()) {
972 art::Exception
e { art::errors::Configuration };
974 <<
" duplicate channels in the configuration:";
975 while (iDup != chMap.end())
e <<
" " << (iDup++)->channel;
BEGIN_PROLOG BeamGateDuration pmtthr physics producers trigtilewindowORS Thresholds
Utilities related to art service access.
DiscriminatePMTwaveformsByChannel::ChannelInfo_t convert(DiscriminatePMTwaveformsByChannel::ChannelConfig const &config)
Utilities for the conversion of trigger gate data formats.
std::optional< typename Optional::value_type > getOptionalValue(Optional const ¶meter)
Returns the value of an optional parameter as std::optional.
Definition of util::enumerate().
Algorithm to produce trigger gates out of optical readout waveforms.
std::vector< icarus::trigger::OpticalTriggerGateData_t > transformIntoOpticalTriggerGate(Gates &&gates)
Returns the trigger gates in serializable format.
static constexpr quantity_t castFrom(U value)
Returns a new quantity initialized with the specified value.
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
Interface to detinfo::DetectorClocks.
util::quantities::counts_as< raw::ADC_Count_t > ADCCounts_t
ADC counts for optical detector readout.
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
Logical multi-level gate associated to one or more readout channels.
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
Utilities to read and write quantities in FHiCL configuration.
A logical multilevel gate for triggering.
A value measured in the specified unit.
Simple type definitions for trigger algorithms.
BEGIN_PROLOG vertical distance to the surface Name
Information from the configuration of PMT readout.
Test of util::counter and support utilities.
short signed int relativeThreshold() const
Threshold relative to the baseline (ticks).
physics producers discrimopdaq OpticalWaveforms
std::string to_string(WindowPattern const &pattern)
size_t NOpDets(int cryostat)
A class exposing an upgraded interface of detinfo::DetectorClocksData.
Functions pulling in STL customization if available.
DataProductPointerMap_t< ArtHandleData_t< Handle > > mapDataProductPointers(art::Event const &event, Handle const &handle)
Creates a map from address of data product element to art pointer to it.
std::vector< triggergate_t > GateData_t
Simple helper functions to deal with FHiCL.
auto zip(Iterables &&...iterables)
Range-for loop helper iterating across many collections at the same time.
raw::Channel_t channelID
Offline channel ID.
Definition of util::values() and util::const_values().
then echo find_global_symbol finds mangled or demangled symbols in libraries echo within LD_LIBRARY_PATH match any symbol that echo contains name echo Default
bool hasChannelID() const
Returns whether the channel ID is set.
std::vector< sbn::V1730channelConfiguration > channels
Configuration of each channel.
Class containing configuration for a V1730 channel.
OpticalTriggerGateData_t GateData_t
Type for gate data access.
Class containing configuration for PMT readout.
constexpr BitMask< Storage > Unset(Flag_t< Storage > flag)
Returns a bit mask which unsets the specified flag.
art framework interface to geometry description
Utilities to map data pointer elements to their art::Ptr.
Class containing configuration for a V1730 board.