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.