20 #include "sbndaq-artdaq-core/Overlays/Common/CAENV1730Fragment.hh"
21 #include "sbndaq-artdaq-core/Overlays/FragmentType.hh"
37 #include "artdaq-core/Data/ContainerFragment.hh"
38 #include "artdaq-core/Data/Fragment.hh"
41 #include "art_root_io/TFileService.h"
42 #include "art/Framework/Services/Registry/ServiceHandle.h"
43 #include "art/Framework/Core/EDProducer.h"
44 #include "art/Framework/Core/ModuleMacros.h"
45 #include "art/Framework/Principal/Run.h"
46 #include "art/Framework/Principal/Event.h"
47 #include "art/Framework/Principal/Handle.h"
48 #include "canvas/Persistency/Provenance/EventID.h"
49 #include "canvas/Persistency/Provenance/Timestamp.h"
50 #include "canvas/Utilities/InputTag.h"
51 #include "messagefacility/MessageLogger/MessageLogger.h"
52 #include "fhiclcpp/types/TableAs.h"
53 #include "fhiclcpp/types/OptionalSequence.h"
54 #include "fhiclcpp/types/Sequence.h"
55 #include "fhiclcpp/types/OptionalAtom.h"
56 #include "fhiclcpp/types/Atom.h"
57 #include "cetlib_except/exception.h"
65 #include <unordered_map>
75 using namespace util::quantities::time_literals;
79 namespace icarus {
class DaqDecoderICARUSPMT; }
420 static std::string listTreeNames(std::string
const& sep =
"\n");
432 static_assert(
sizeof(
int) >= 4U);
434 int seconds = std::numeric_limits<int>::min();
436 unsigned int nanoseconds = std::numeric_limits<unsigned int>::max();
440 long long int time = std::numeric_limits<long long int>::min();
459 fhicl::Atom<unsigned short int> ChannelIndex {
462 (
"index of the channel on the board these settings pertain")
466 fhicl::OptionalAtom<bool> Skip {
469 "set to true to force skipping this channel, false to force saving it"
473 fhicl::Atom<bool> OnlyOnGlobalTrigger {
476 (
"save this channel only if its data includes global trigger time"),
480 fhicl::Atom<std::uint16_t> MinSpan {
483 "discard this channel if its span (maximum minus minimum)"
484 " is smallerthan this"
489 fhicl::Atom<raw::Channel_t> Channel {
491 fhicl::Comment(
"Off-line channel ID associated to this board channel"),
495 fhicl::Atom<std::string> InstanceName {
498 (
"name of the data product instance where to add this channel"),
505 fhicl::Atom<std::string>
Name {
507 fhicl::Comment(
"board name, as specified in the DAQ configuration")
510 fhicl::OptionalAtom<unsigned int> FragmentID {
512 fhicl::Comment(
"ID of the fragments associated with the board")
515 fhicl::Atom<nanoseconds> TriggerDelay {
518 (
"from delay from the trigger timestamp to the PMT trigger [ns]"),
522 fhicl::Atom<nanoseconds> TTTresetDelay {
525 (
"assume that V1730 counter (Trigger Time Tag) is reset every second"),
529 fhicl::OptionalSequence<fhicl::Table<ChannelSetupConfig>> SpecialChannels {
531 fhicl::Comment(
"special settings for selected channels on the board")
543 fhicl::Sequence<art::InputTag> FragmentsLabels {
544 Name(
"FragmentsLabels"),
545 Comment(
"data product candidates with the PMT fragments from DAQ"),
546 std::vector<art::InputTag>{
"daq:CAENV1730",
"daq:ContainerCAENV1730" }
549 fhicl::Atom<bool> SurviveExceptions {
550 Name(
"SurviveExceptions"),
552 (
"when the decoding module throws an exception, print a message and move on"),
556 fhicl::Atom<bool> DiagnosticOutput {
557 Name(
"DiagnosticOutput"),
558 Comment(
"enable additional console output"),
562 fhicl::Atom<bool> PacketDump {
564 Comment(
"enable dump of the whole V1730 data (huge)"),
568 fhicl::Atom<bool> RequireKnownBoards {
569 Name(
"RequireKnownBoards"),
571 (
"all readout boards in input must be known (setup+PMT configuration)"),
576 Name(
"RequireBoardConfig"),
578 (
"all readout boards in setup must have a matching PMT configuration"),
582 fhicl::OptionalAtom<art::InputTag> PMTconfigTag {
583 Name(
"PMTconfigTag"),
584 Comment(
"input tag for the PMT readout board configuration information")
588 <fhicl::TableAs<daq::details::BoardSetup_t, BoardSetupConfig>>
591 Comment(
"list of the setup settings for all relevant V1730 boards")
594 fhicl::OptionalAtom<art::InputTag> TriggerTag {
596 Comment(
"input tag for the global trigger object (sbn::ExtraTriggerInfo)")
599 fhicl::OptionalAtom<bool> TTTresetEverySecond {
600 Name(
"TTTresetEverySecond"),
602 (
"assume that V1730 counter (Trigger Time Tag) is reset every second")
608 (
"produces the specified ROOT trees (" + listTreeNames(
",") +
")"),
609 std::vector<std::string>{}
612 fhicl::Atom<bool> SkipWaveforms {
613 Name(
"SkipWaveforms"),
614 Comment(
"do not decode and produce waveforms"),
618 fhicl::Atom<bool> DropRawDataAfterUse {
619 Name(
"DropRawDataAfterUse"),
620 Comment(
"drop PMT data fragments from memory after use"),
624 fhicl::Atom<std::string> LogCategory {
626 Comment(
"name of the category for message stream"),
636 = std::numeric_limits<electronics_time>::min();
646 void beginRun(art::Run& run)
override;
649 void produce(art::Event& event)
override;
652 void endJob()
override;
662 artdaq::Fragment::fragment_id_t fragmentID
663 = std::numeric_limits<artdaq::Fragment::fragment_id_t>::max();
665 unsigned int eventCounter = 0U;
666 std::uint32_t TTT = 0U;
667 std::uint16_t enabledChannels = 0U;
668 std::size_t nSamplesPerChannel = 0U;
669 std::uint16_t
const* data =
nullptr;
684 {
return specialChannelSetup? *specialChannelSetup: DefaultChannelSetup; }
693 unsigned int gateCount = 0U;
705 bool onGlobal =
false;
708 std::uint16_t minSample = std::numeric_limits<std::uint16_t>::max();
710 std::uint16_t maxSample = std::numeric_limits<std::uint16_t>::max();
714 {
return (maxSample > minSample)? (maxSample - minSample): 0; }
718 {
return waveform < than.
waveform; }
791 unsigned int fNFailures = 0U;
823 NeededBoardInfo_t fetchNeededBoardInfo(
825 unsigned int fragmentID
829 static unsigned int extractTriggerTimeTag(artdaq::Fragment
const& fragment);
855 template <std::
size_t NBits,
typename T>
856 static constexpr std::pair<std::array<std::size_t, NBits>, std::size_t>
857 setBitIndices(T
value) noexcept;
876 unsigned int fragCount = 0U;
879 unsigned long int TriggerTimeTag = 0;
888 double waveformTime = std::numeric_limits<double>::lowest();
890 unsigned int waveformSize = 0U;
892 unsigned int triggerBits = 0x0;
894 unsigned int gateCount = 0U;
897 bool onGlobalTrigger =
false;
903 TTree* tree =
nullptr;
918 TriggerInfo_t fetchTriggerTimestamp(art::Event
const& event)
const;
961 {
return static_cast<long long int>(
a) - static_cast<long long int>(b); }
965 static constexpr std::size_t effectivePMTboardFragmentID
966 (artdaq::Fragment::fragment_id_t
id)
967 {
return id & 0x0fff; }
979 artdaq::Fragments
const& readInputFragments(art::Event
const& event)
const;
982 void checkFragmentType(artdaq::Fragment
const& artdaqFragment)
const;
986 artdaq::FragmentPtrs makeFragmentCollection
987 (artdaq::Fragment
const& sourceFragment)
const;
990 artdaq::FragmentPtrs makeFragmentCollectionFromFragment
991 (artdaq::Fragment
const& sourceFragment)
const;
994 artdaq::FragmentPtrs makeFragmentCollectionFromContainerFragment
995 (artdaq::Fragment
const& sourceFragment)
const;
998 std::vector<ProtoWaveform_t> processBoardFragments(
999 artdaq::FragmentPtrs
const& artdaqFragment,
1010 unsigned int mergeWaveforms(std::vector<ProtoWaveform_t>& waveforms)
const;
1013 void sortWaveforms(std::vector<ProtoWaveform_t>& waveforms)
const;
1016 std::vector<ProtoWaveform_t const*> findWaveformsWithNominalTrigger
1017 (std::vector<ProtoWaveform_t>
const& waveforms)
const;
1023 bool containsGlobalTrigger(
electronics_time time, std::size_t nTicks)
const;
1028 std::vector<ProtoWaveform_t>& allWaveforms,
1029 std::vector<std::size_t>
const&
indices
1036 {
return waveformStartTime(wf.
waveform); }
1039 {
return waveformStartTime(wf) +
fOpticalTick * wf.size(); }
1042 {
return waveformEndTime(wf.
waveform); }
1060 std::vector<ProtoWaveform_t> processFragment(
1061 artdaq::Fragment
const& artdaqFragment,
1078 std::vector<ProtoWaveform_t> createFragmentWaveforms(
1086 (artdaq::Fragment
const& artdaqFragment)
const;
1089 static BoardID_t extractFragmentBoardID(artdaq::Fragment
const& fragment);
1093 (artdaq::Fragment::fragment_id_t fragment_id)
const;
1096 std::set<std::string> getAllInstanceNames()
const;
1099 void checkBoardSetup
1100 (std::vector<daq::details::BoardSetup_t>
const& allBoardSetup)
const;
1106 void usesEventInfo();
1109 void initTrees(std::vector<std::string>
const& treeNames);
1115 void initFragmentsTree();
1118 void fillTreeEventID
1126 void fillPMTfragmentTree(
1134 static std::string
const& treeName(
DataTrees treeID);
1153 template <
typename T>
1154 std::vector<T>& appendTo(std::vector<T>& dest, std::vector<T>&& src) {
1155 if (dest.empty()) dest = std::move(src);
1157 dest.reserve(dest.size() + src.size());
1158 std::move(src.begin(), src.end(), std::back_inserter(dest));
1165 template <
typename Coll,
typename T>
1166 bool contains(Coll
const& coll, T
const&
value) {
1197 std::vector<DaqDecoderICARUSPMT::BoardSetupConfig::ChannelSetupConfig>{}
1201 bs.channelSettings.at(chConfig.ChannelIndex()) = {
1204 , chConfig.OnlyOnGlobalTrigger()
1205 , chConfig.MinSpan()
1206 , chConfig.InstanceName()
1209 catch (std::out_of_range
const&) {
1210 throw art::Exception(art::errors::Configuration)
1211 <<
"Configuration requested for invalid channel index "
1212 << chConfig.ChannelIndex() <<
" of the board '"
1213 << config.
Name() <<
"'\n";
1238 (
int sec,
unsigned int ns)
1239 : time {
static_cast<long long int>(sec) * 1
'000'000
'000LL + ns }
1244 //------------------------------------------------------------------------------
1245 constexpr icarus::DaqDecoderICARUSPMT::SplitTimestamp_t::SplitTimestamp_t
1246 (long long int triggerTime)
1247 : time { triggerTime }
1249 static_cast<int>(time / 1'000
'000'000),
1250 static_cast<unsigned int>(time % 1
'000'000
'000) // nanoseconds
1255 //------------------------------------------------------------------------------
1258 std::ostream& operator<<
1259 (std::ostream& out, DaqDecoderICARUSPMT::SplitTimestamp_t const& time)
1261 out << time.split.seconds << '.
'
1262 << std::setfill('0
') << std::setw(9) << time.split.nanoseconds;
1264 } // operator<< (std::ostream&, PMTDecoder::SplitTimestamp_t)
1266 } // namespace icarus
1269 //------------------------------------------------------------------------------
1270 // --- icarus::DaqDecoderICARUSPMT
1271 //------------------------------------------------------------------------------
1272 // --- template implementation
1273 //------------------------------------------------------------------------------
1274 template <std::size_t NBits, typename T>
1275 constexpr std::pair<std::array<std::size_t, NBits>, std::size_t>
1276 icarus::DaqDecoderICARUSPMT::setBitIndices(T value) noexcept {
1278 std::pair<std::array<std::size_t, NBits>, std::size_t> res;
1279 auto& [ indices, nSetBits ] = res;
1280 for (std::size_t& index: indices) {
1281 index = (value & 1)? nSetBits++: NBits;
1286 } // icarus::DaqDecoderICARUSPMT::setBitIndices()
1289 //------------------------------------------------------------------------------
1290 // --- static definitions
1291 //------------------------------------------------------------------------------
1292 icarus::DaqDecoderICARUSPMT::AllChannelSetup_t const
1293 icarus::DaqDecoderICARUSPMT::NeededBoardInfo_t::DefaultChannelSetup;
1295 //------------------------------------------------------------------------------
1296 icarus::DaqDecoderICARUSPMT::TreeNameList_t const
1297 icarus::DaqDecoderICARUSPMT::TreeNames
1298 = icarus::DaqDecoderICARUSPMT::initTreeNames();
1300 auto icarus::DaqDecoderICARUSPMT::initTreeNames() -> TreeNameList_t {
1301 TreeNameList_t names;
1302 names[static_cast<std::size_t>(DataTrees::Fragments)] = "PMTfragments";
1304 } // icarus::DaqDecoderICARUSPMT::initTreeNames()
1307 //------------------------------------------------------------------------------
1308 std::string const& icarus::DaqDecoderICARUSPMT::treeName(DataTrees treeID)
1309 { return TreeNames[static_cast<std::size_t>(treeID)]; }
1312 //------------------------------------------------------------------------------
1313 std::string icarus::DaqDecoderICARUSPMT::listTreeNames
1314 (std::string const& sep /* = " " */)
1317 for (std::string const& name: TreeNames) {
1318 if (!l.empty()) l += sep;
1331 : art::EDProducer(params)
1332 , fInputTags{ params().FragmentsLabels() }
1333 , fSurviveExceptions{ params().SurviveExceptions() }
1334 , fDiagnosticOutput{ params().DiagnosticOutput() }
1335 , fPacketDump{ params().PacketDump() }
1336 , fRequireKnownBoards{ params().RequireKnownBoards() }
1337 , fRequireBoardConfig{ params().RequireBoardConfig() }
1338 , fPMTconfigTag{ params().PMTconfigTag() }
1339 , fTriggerTag{ params().TriggerTag() }
1340 , fTTTresetEverySecond
1341 { params().TTTresetEverySecond().value_or(fTriggerTag.has_value()) }
1342 , fBoardSetup{ params().BoardSetup() }
1343 , fSkipWaveforms{ params().SkipWaveforms() }
1344 , fDropRawDataAfterUse{ params().DropRawDataAfterUse() }
1347 { art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob() }
1348 , fChannelMap{ *(art::ServiceHandle<icarusDB::IICARUSChannelMap const>{}) }
1350 , fNominalTriggerTime{ fDetTimings.TriggerTime() }
1355 checkBoardSetup(fBoardSetup);
1360 for (art::InputTag
const& inputTag: fInputTags)
1361 consumes<artdaq::Fragments>(inputTag);
1362 if (fPMTconfigTag) consumes<sbn::PMTconfiguration>(*fPMTconfigTag);
1364 consumes<std::vector<sbn::ExtraTriggerInfo>>(*fTriggerTag);
1365 if (contains(params().DataTrees(), treeName(DataTrees::Fragments)))
1366 consumes<std::vector<raw::Trigger>>(*fTriggerTag);
1372 if (!fSkipWaveforms) {
1373 for (std::string
const& instanceName: getAllInstanceNames())
1374 produces<std::vector<raw::OpDetWaveform>>(instanceName);
1380 initTrees(params().DataTrees());
1387 log <<
"Configuration:"
1388 <<
"\n * data from one of " << fInputTags.size() <<
" data products:";
1389 for (art::InputTag
const& inputTag: fInputTags)
1390 log <<
" '" << inputTag.encode() <<
"'";
1392 <<
"\n * boards with setup: " << fBoardSetup.size();
1394 log <<
"\n * PMT configuration from '" << fPMTconfigTag->encode() <<
"'";
1396 log <<
"\n * PMT configuration not used (and some corrections will be skipped)";
1398 log <<
"\n * trigger information from: '" << fTriggerTag->encode() <<
'\'';
1400 log <<
"\n * trigger time from event timestamp [fallback]";
1401 if (fRequireKnownBoards) {
1402 log <<
"\n * all readout boards in input must be known (from `"
1403 << params().BoardSetup.name() <<
"` or `"
1404 << params().PMTconfigTag.name() <<
"`)"
1408 log <<
"\n * readout boards with no information (from neither `"
1409 << params().BoardSetup.name() <<
"` or `"
1410 << params().PMTconfigTag.name()
1411 <<
"`) are processed at the best we can (skipping corrections)"
1414 if (fRequireBoardConfig) {
1415 log <<
"\n * all readout boards in `"
1416 << params().BoardSetup.name()
1417 <<
"` must appear in the PMT configuration from `"
1418 << params().PMTconfigTag.name() <<
"`"
1422 log <<
"\n * all readout boards in `"
1423 << params().BoardSetup.name()
1424 <<
"` may lack a matching PMT configuration from `"
1425 << params().PMTconfigTag.name() <<
"`"
1428 if (fSkipWaveforms) {
1429 log <<
"\n * PMT WAVEFORMS WILL NOT BE DECODED AND STORED";
1436 if (fChannelMap.nPMTfragmentIDs() == 0) {
1437 throw cet::exception(
"DaqDecoderICARUSPMT")
1438 <<
"Channel mapping database does not report any PMT fragment ID!\n";
1453 UpdatePMTConfiguration(PMTconfig);
1465 fDataCacheRemover.useEvent(event);
1470 TriggerInfo_t
const triggerInfo = fetchTriggerTimestamp(event);
1474 log <<
"Trigger time ('" << fTriggerTag->encode() <<
"'): ";
1476 log <<
"Trigger from event timestamp: ";
1477 log << triggerInfo.time <<
" s, bits: "
1479 if (triggerInfo.bits) {
1481 for (std::string
const&
name:
names(triggerInfo.bits)) log <<
' ' <<
name;
1484 if (fTriggerTag) log <<
", spill count: " << triggerInfo.gateCount;
1492 if (fEventInfo) fillTreeEventID(event, *fEventInfo);
1497 std::vector<ProtoWaveform_t> protoWaveforms;
1509 std::unordered_map<BoardID_t, unsigned int> boardCounts;
1510 bool duplicateBoards =
false;
1512 auto const& fragments = readInputFragments(event);
1514 for (artdaq::Fragment
const& fragment: fragments) {
1516 artdaq::FragmentPtrs
const& fragmentCollection
1517 = makeFragmentCollection(fragment);
1519 if (
empty(fragmentCollection)) {
1520 mf::LogWarning(
"DaqDecoderICARUSPMT")
1521 <<
"Found a data fragment (ID=" << extractFragmentBoardID(fragment)
1522 <<
") containing no data.";
1526 BoardID_t
const boardID
1527 = extractFragmentBoardID(*(fragmentCollection.front()));
1528 if (++boardCounts[boardID] > 1U) duplicateBoards =
true;
1532 processBoardFragments(fragmentCollection, triggerInfo)
1538 catch (cet::exception
const&
e) {
1539 if (!fSurviveExceptions)
throw;
1540 mf::LogError(
"DaqDecoderICARUSPMT")
1541 <<
"Error while attempting to decode PMT data:\n" << e.what() <<
'\n';
1542 protoWaveforms.clear();
1546 if (!fSurviveExceptions)
throw;
1547 mf::LogError(
"DaqDecoderICARUSPMT")
1548 <<
"Error while attempting to decode PMT data.\n";
1549 protoWaveforms.clear();
1553 if (duplicateBoards) {
1554 mf::LogWarning log {
"DaqDecoderICARUSPMT" };
1555 log <<
"found multiple data product entries for the same board:";
1556 for (
auto [ boardID,
count ]: boardCounts) {
1557 if (
count < 2U)
continue;
1558 log <<
" " << std::hex << boardID << std::dec <<
" (x" <<
count <<
");";
1565 fDataCacheRemover.removeCachedProducts();
1570 sortWaveforms(protoWaveforms);
1572 if (!fSkipWaveforms) {
1573 std::vector<ProtoWaveform_t const*>
const waveformsWithTrigger
1574 = findWaveformsWithNominalTrigger(protoWaveforms);
1575 mf::LogTrace(
fLogCategory) << waveformsWithTrigger.size() <<
"/"
1576 << protoWaveforms.size() <<
" decoded waveforms include trigger time ("
1577 << fNominalTriggerTime <<
").";
1584 if (!fSkipWaveforms) {
1586 std::map<std::string, std::vector<raw::OpDetWaveform>> waveformProducts;
1587 for (std::string
const& instanceName: getAllInstanceNames())
1588 waveformProducts.emplace(instanceName, std::vector<raw::OpDetWaveform>{});
1589 for (ProtoWaveform_t& waveform: protoWaveforms) {
1594 (waveform.onGlobal || !waveform.channelSetup->onGlobalOnly)
1595 && (waveform.span() >= waveform.channelSetup->minSpan)
1598 if (!keep)
continue;
1599 waveformProducts.at(waveform.channelSetup->category).push_back
1600 (std::move(waveform.waveform));
1604 for (
auto&& [ category, waveforms ]: waveformProducts) {
1606 << waveforms.size() <<
" PMT waveforms saved for "
1607 << (category.empty()?
"standard": category) <<
" instance.";
1609 std::make_unique<std::vector<raw::OpDetWaveform>>(std::move(waveforms)),
1621 if (fNFailures > 0U) {
1622 mf::LogError(
fLogCategory) <<
"Encountered errors on " << fNFailures
1623 <<
" events. Errors were ignored.";
1631 (art::Event
const& event)
const
1633 art::Handle<artdaq::Fragments> handle;
1634 art::InputTag selectedInputTag;
1635 for (art::InputTag
const& inputTag: fInputTags) {
1638 <<
"DaqDecoderICARUSPMT trying data product: '" << inputTag.encode()
1641 auto const& thisHandle =
event.getHandle<artdaq::Fragments>(inputTag);
1642 if (!thisHandle.isValid() || thisHandle->empty())
continue;
1645 <<
" => data product: '" << inputTag.encode() <<
"' is present and has "
1646 << thisHandle->size() <<
" entries";
1648 if (!selectedInputTag.empty()) {
1649 throw cet::exception(
"DaqDecoderICARUSPMT")
1650 <<
"Found multiple suitable input candidates: '"
1651 << inputTag.encode() <<
"' and '" << selectedInputTag <<
"'\n";
1653 selectedInputTag = inputTag;
1654 handle = thisHandle;
1657 if (!handle.isValid()) {
1658 cet::exception e {
"DaqDecoderICARUSPMT" };
1659 e <<
"No suitable input data product found among:";
1660 for (art::InputTag
const& inputTag: fInputTags)
1661 e <<
" '" << inputTag.encode() <<
"'";
1665 if (fDropRawDataAfterUse) fDataCacheRemover.registerHandle(handle);
1673 (std::vector<ProtoWaveform_t>
const& waveforms)
const
1674 -> std::vector<ProtoWaveform_t const*>
1676 std::vector<ProtoWaveform_t const*> matchedWaveforms;
1677 for (ProtoWaveform_t
const& waveform: waveforms) {
1678 if (waveform.onGlobal) matchedWaveforms.push_back(&waveform);
1680 return matchedWaveforms;
1688 return (fNominalTriggerTime >= time)
1689 && (fNominalTriggerTime < time + nTicks *
fOpticalTick);
1697 return containsGlobalTrigger
1706 fBoardInfoLookup.emplace(matchBoardConfigurationAndSetup(PMTconfig));
1709 <<
"Board information as cached:\n" << *fBoardInfoLookup;
1744 std::vector<std::pair<std::string, sbn::V1730Configuration const*>>
1747 if (!PMTconfig->
boards.empty())
1748 configByName.reserve(PMTconfig->
boards.size());
1750 configByName.emplace_back(boardConfig.
boardName, &boardConfig);
1751 std::sort(configByName.begin(), configByName.end());
1755 auto findPMTconfig = [
this, &configByName]
1758 if (!hasPMTconfiguration())
return nullptr;
1759 auto const* ppBoardConfig
1761 if (!ppBoardConfig) {
1762 if (!fRequireBoardConfig)
return nullptr;
1763 throw cet::exception(
"DaqDecoderICARUSPMT")
1764 <<
"No DAQ configuration found for PMT readout board '"
1766 "If this is expected, you may skip this check by setting "
1767 "DaqDecoderICARUSPMT module configuration `RequireBoardConfig`"
1771 return ppBoardConfig->second;
1780 std::string
const& boardName = boardSetup.name;
1786 if (boardSetup.hasFragmentID()
1787 && (boardSetup.fragmentID != pBoardConfig->
fragmentID)
1789 throw cet::exception(
"DaqDecoderICARUSPMT")
1790 <<
"Board '" << boardName <<
"' has fragment ID "
1791 << std::hex << pBoardConfig->
fragmentID << std::dec
1792 <<
" but it is set up as "
1793 << std::hex << boardSetup.fragmentID << std::dec
1798 if (boardSetup.hasFragmentID()) {
1800 <<
"Board '" << boardName
1801 <<
"' has no configuration information;"
1802 " some time stamp corrections will be skipped.";
1807 <<
"Board '" << boardName
1808 <<
"' can't be associated to a fragment ID;"
1809 " its time stamp corrections will be skipped.";
1816 unsigned int const fragmentID
1817 = pBoardConfig? pBoardConfig->
fragmentID: boardSetup.fragmentID;
1831 boardInfoByFragment.push_back({
1835 std::move(boardFacts)
1847 unsigned int fragmentID
1848 )
const -> NeededBoardInfo_t {
1852 return NeededBoardInfo_t{
1854 ((boardInfo && boardInfo->config)
1855 ? boardInfo->config->boardName: (
"<ID=" +
std::to_string(fragmentID)))
1857 , ((boardInfo && boardInfo->config)
1861 , (boardInfo? boardInfo->facts.preTriggerTime: nanoseconds{ 0.0 })
1863 , ((boardInfo && boardInfo->setup)
1864 ? boardInfo->setup->triggerDelay: nanoseconds{ 0.0 })
1866 , ((boardInfo && boardInfo->setup)
1867 ? boardInfo->setup->TTTresetDelay: nanoseconds{ 0.0 })
1868 , ((boardInfo && boardInfo->setup)?
1869 &(boardInfo->setup->channelSettings):
nullptr)
1877 (art::Event
const& event)
const -> TriggerInfo_t
1881 return { SplitTimestamp_t(event.time().value()), 0U };
1884 auto const& extraTrigger
1886 if (!extraTrigger.isValid()) {
1890 throw cet::exception(
"DaqDecoderICARUSPMT")
1891 <<
"Extra trigger information from '"
1892 << fTriggerTag->encode() <<
"' is marked as invalid!\n";
1895 if (fDiagnosticOutput) {
1897 <<
"Extended trigger information:\n" << extraTrigger;
1900 auto const& triggers
1901 =
event.getProduct<std::vector<raw::Trigger>>(*fTriggerTag);
1902 if (triggers.size() != 1U) {
1905 throw cet::exception(
"DaqDecoderICARUSPMT")
1906 <<
"Found " << triggers.size() <<
" raw::Trigger from '"
1907 << fTriggerTag->encode() <<
"', can deal only with 1.\n";
1911 long long int const relBeamGate = timestampDiff
1912 (extraTrigger.beamGateTimestamp, extraTrigger.triggerTimestamp);
1914 unsigned int const gateCount = extraTrigger.gateID;
1918 {
static_cast<long long int>(extraTrigger.triggerTimestamp) }
1929 (artdaq::Fragment
const& sourceFragment)
const
1931 switch (sourceFragment.type()) {
1932 case sbndaq::FragmentType::CAENV1730:
1933 return makeFragmentCollectionFromFragment(sourceFragment);
1934 case artdaq::Fragment::ContainerFragmentType:
1935 return makeFragmentCollectionFromContainerFragment(sourceFragment);
1937 throw cet::exception(
"DaqDecoderICARUSPMT")
1938 <<
"Unexpected PMT data product fragment type: "
1939 <<
static_cast<int>(sourceFragment.type()) <<
" ('"
1940 << sbndaq::fragmentTypeToString
1941 (static_cast<sbndaq::FragmentType>(sourceFragment.type()))
1948 artdaq::FragmentPtrs
1950 (artdaq::Fragment
const& sourceFragment)
const
1952 assert(sourceFragment.type() == sbndaq::FragmentType::CAENV1730);
1953 artdaq::FragmentPtrs fragColl;
1954 fragColl.push_back(std::make_unique<artdaq::Fragment>(sourceFragment));
1960 artdaq::FragmentPtrs
1962 (artdaq::Fragment
const& sourceFragment)
const
1964 assert(sourceFragment.type() == artdaq::Fragment::ContainerFragmentType);
1965 artdaq::ContainerFragment
const containerFragment{ sourceFragment };
1967 if (containerFragment.block_count() == 0)
return {};
1969 artdaq::FragmentPtrs fragColl;
1970 for (
auto const iFrag:
util::counter(containerFragment.block_count()))
1971 fragColl.push_back(containerFragment.at(iFrag));
1979 (artdaq::Fragment
const& artdaqFragment)
const
1981 if (artdaqFragment.type() == sbndaq::FragmentType::CAENV1730)
return;
1983 throw cet::exception(
"DaqDecoderICARUSPMT")
1984 <<
"Unexpected PMT fragment data type: '"
1985 << sbndaq::fragmentTypeToString
1986 (static_cast<sbndaq::FragmentType>(artdaqFragment.type()))
1994 artdaq::FragmentPtrs
const& artdaqFragments,
1995 TriggerInfo_t
const& triggerInfo
1996 ) -> std::vector<ProtoWaveform_t> {
1998 if (artdaqFragments.empty())
return {};
2000 artdaq::Fragment
const& referenceFragment = *(artdaqFragments.front());
2001 assert(&referenceFragment);
2003 checkFragmentType(referenceFragment);
2005 NeededBoardInfo_t
const boardInfo
2006 = neededBoardInfo(artdaqFragments.front()->fragmentID());
2009 <<
" - " << boardInfo.name <<
": " << artdaqFragments.size()
2012 std::vector<ProtoWaveform_t> waveforms;
2013 for (artdaq::FragmentPtr
const& fragment: artdaqFragments)
2014 appendTo(waveforms, processFragment(*fragment, boardInfo, triggerInfo));
2016 mergeWaveforms(waveforms);
2018 return { waveforms };
2025 artdaq::Fragment
const& artdaqFragment,
2026 NeededBoardInfo_t
const& boardInfo,
2027 TriggerInfo_t
const& triggerInfo
2028 ) -> std::vector<ProtoWaveform_t> {
2030 checkFragmentType(artdaqFragment);
2034 <<
"\n" << std::string(80,
'-')
2036 <<
"\n" << std::string(80,
'-')
2040 FragmentInfo_t
const fragInfo = extractFragmentInfo(artdaqFragment);
2042 auto const timeStamp
2043 = fragmentWaveformTimestamp(fragInfo, boardInfo, triggerInfo.time);
2045 if (fTreeFragment) fillPMTfragmentTree(fragInfo, triggerInfo, timeStamp);
2047 return ((timeStamp != NoTimestamp) && !fSkipWaveforms)
2048 ? createFragmentWaveforms(fragInfo, boardInfo.channelSetup(), timeStamp)
2049 : std::vector<ProtoWaveform_t>{}
2057 FragmentInfo_t
const& fragInfo, AllChannelSetup_t
const& channelSetup,
2059 )
const -> std::vector<ProtoWaveform_t>
2062 assert(timeStamp != NoTimestamp);
2064 std::vector<ProtoWaveform_t> protoWaveforms;
2066 std::optional<mf::LogVerbatim> diagOut;
2070 = fChannelMap.getChannelIDPairVec
2071 (effectivePMTboardFragmentID(fragInfo.fragmentID))
2075 std::vector<std::uint16_t> wvfm(fragInfo.nSamplesPerChannel);
2079 bool const onGlobal = containsGlobalTrigger(timeStamp, wvfm.size());
2081 auto channelNumberToChannel
2082 = [&digitizerChannelVec](
unsigned short int channelNumber) ->
raw::Channel_t
2084 for (
auto const [ chNo, chID ]: digitizerChannelVec)
2085 if (chNo == channelNumber)
return chID;
2090 (*diagOut) <<
" " << digitizerChannelVec.size() <<
" channels:";
2092 std::size_t iNextChunk = 0;
2093 for (
unsigned short int const channelNumber:
util::counter(16U)) {
2095 if ((fragInfo.enabledChannels & (1 << channelNumber)) == 0) {
2097 (*diagOut) <<
" " << channelNumber <<
" [disabled];";
2101 std::size_t
const iChunk = iNextChunk++;
2104 = channelSetup.at(channelNumber);
2108 <<
"Channel number " << channelNumber <<
" of board 0x"
2109 << std::hex << fragInfo.fragmentID << std::dec
2110 <<
" is enabled but is requested to be skipped.";
2118 ? thisChannelSetup.
channelID: channelNumberToChannel(channelNumber);
2120 if (!thisChannelSetup.
isChannel(channel)) {
2131 throw cet::exception(
"DaqDecoderICARUSPMT")
2132 <<
"Channel number " << channelNumber <<
" of board 0x"
2133 << std::hex << fragInfo.fragmentID << std::dec
2134 <<
" is not associated to any channel ID"
2135 <<
" but was demanded to be saved.\n"
2139 <<
"Channel number " << channelNumber <<
" of board 0x"
2140 << std::hex << fragInfo.fragmentID << std::dec
2141 <<
" is enabled but not associated to any channel ID:"
2142 " it will be skipped.";
2145 assert(thisChannelSetup.
isChannel(channel));
2158 std::size_t
const ch_offset = iChunk * fragInfo.nSamplesPerChannel;
2159 std::copy_n(fragInfo.data + ch_offset, wvfm.size(), wvfm.begin());
2164 auto const [ itMin, itMax ] = std::minmax_element(wvfm.begin(), wvfm.end());
2165 protoWaveforms.push_back({
2174 log <<
"PMT channel " << dumpChannel(protoWaveforms.back())
2175 <<
" has " << wvfm.size() <<
" samples (read from entry #" << iChunk
2176 <<
" in fragment data) starting at electronics time " << timeStamp;
2177 if (protoWaveforms.back().onGlobal) log <<
", on global trigger";
2178 if (!protoWaveforms.back().channelSetup->category.empty()) {
2179 log <<
"; category: '" << protoWaveforms.back().channelSetup->category
2188 <<
" - number of waveforms decoded: " << protoWaveforms.size();
2189 if (!protoWaveforms.empty() && protoWaveforms.back().onGlobal)
2190 (*diagOut) <<
" - matches global trigger!";
2193 return protoWaveforms;
2200 (std::vector<ProtoWaveform_t>& waveforms)
const
2202 std::size_t
const nWaveforms = waveforms.size();
2203 if (nWaveforms < 2)
return 0U;
2208 {
return ((a - 0.01_ns) < b) && (b < a +
fOpticalTick / 2.0); };
2210 sortWaveforms(waveforms);
2213 std::vector<std::vector<std::size_t>> waveformGroups;
2214 std::size_t iWave = 0U;
2217 std::vector<std::size_t>
group{ iWave };
2222 = waveforms[iWave].waveform.ChannelNumber();
2223 while (++iWave < nWaveforms) {
2226 if (!matchTimes(currentEnd, waveformStartTime(waveform)))
break;
2227 group.push_back(iWave);
2228 currentEnd = waveformEndTime(waveform);
2231 waveformGroups.push_back(std::move(
group));
2232 }
while (iWave < nWaveforms);
2234 std::vector<ProtoWaveform_t> mergedWaveforms;
2235 mergedWaveforms.reserve(waveformGroups.size());
2236 for (
auto const&
group: waveformGroups)
2237 mergedWaveforms.push_back(mergeWaveformGroup(waveforms,
group));
2238 waveforms = std::move(mergedWaveforms);
2239 return nWaveforms - waveforms.size();
2245 std::vector<ProtoWaveform_t>& allWaveforms,
2246 std::vector<std::size_t>
const&
indices
2247 )
const -> ProtoWaveform_t {
2250 throw std::logic_error
2251 {
"DaqDecoderICARUSPMT::mergeWaveformGroup(): empty waveform group." };
2254 auto itIndex =
indices.begin();
2255 auto const iend =
indices.end();
2256 ProtoWaveform_t mergedWaveform{ std::move(allWaveforms.at(*itIndex)) };
2266 while (++itIndex != iend) {
2267 ProtoWaveform_t& wf = allWaveforms.at(*itIndex);
2268 mf::LogTrace(
"DaqDecoderICARUSPMT")
2269 <<
" - extending waveform channel=" << dumpChannel(mergedWaveform)
2270 <<
" time=" << waveformStartTime(mergedWaveform)
2271 <<
" -- " << waveformEndTime(mergedWaveform)
2272 <<
" (" << mergedWaveform.waveform.size()
2273 <<
" samples) with waveform [#" << (*itIndex) <<
"] channel="
2274 << dumpChannel(wf) <<
" at time=" << waveformStartTime(wf.waveform)
2275 <<
" (" << wf.waveform.size() <<
" samples)"
2277 if (mergedWaveform.waveform.ChannelNumber() != wf.waveform.ChannelNumber())
2279 throw std::logic_error{
2280 "DaqDecoderICARUSPMT::mergeWaveformGroup(): "
2281 "attempt to merge waveforms from channels "
2286 if (wf.waveform.empty()) {
2287 throw std::logic_error{
2288 "DaqDecoderICARUSPMT::mergeWaveformGroup(): "
2289 "attempt to merge a waveform (channel "
2291 +
", timestamp " +
std::to_string(wf.waveform.TimeStamp()) +
" again"
2294 if (wf.channelSetup->category != mergedWaveform.channelSetup->category) {
2295 throw std::logic_error{
2296 "DaqDecoderICARUSPMT::mergeWaveformGroup(): "
2297 "attempt to merge a waveform (channel "
2299 +
" of category '" + mergedWaveform.channelSetup->category
2300 +
"' with a waveform (channel "
2302 +
" of the different category '" + wf.channelSetup->category +
"'"
2305 if (wf.channelSetup != mergedWaveform.channelSetup) {
2306 throw std::logic_error{
2307 "DaqDecoderICARUSPMT::mergeWaveformGroup(): "
2308 "attempt to merge a waveform (channel "
2310 +
" with channel settings different than the other waveform (channel "
2315 std::size_t
const expectedSize [[maybe_unused]]
2316 = mergedWaveform.waveform.size() + wf.waveform.size();
2317 appendTo(mergedWaveform.waveform, std::move(wf.waveform));
2318 mergedWaveform.onGlobal |= wf.onGlobal;
2319 if (wf.minSample < mergedWaveform.minSample)
2320 mergedWaveform.minSample = wf.minSample;
2321 if (wf.maxSample > mergedWaveform.maxSample)
2322 mergedWaveform.maxSample = wf.maxSample;
2323 assert(wf.waveform.empty());
2324 assert(mergedWaveform.waveform.size() == expectedSize);
2326 return mergedWaveform;
2332 FragmentInfo_t
const& fragInfo,
2333 TriggerInfo_t
const& triggerInfo,
2337 if (!fTreeFragment)
return;
2339 fTreeFragment->data.fragmentID = fragInfo.fragmentID;
2340 fTreeFragment->data.fragCount = fragInfo.eventCounter;
2341 fTreeFragment->data.TriggerTimeTag = fragInfo.TTT;
2342 fTreeFragment->data.trigger = triggerInfo.time;
2343 fTreeFragment->data.relBeamGate = triggerInfo.relBeamGateTime;
2344 fTreeFragment->data.fragTime
2345 = {
static_cast<long long int>(fragInfo.fragmentTimestamp) };
2346 fTreeFragment->data.waveformTime = waveformTimestamp.value();
2347 fTreeFragment->data.waveformSize = fragInfo.nSamplesPerChannel;
2348 fTreeFragment->data.triggerBits = triggerInfo.bits;
2349 fTreeFragment->data.gateCount = triggerInfo.gateCount;
2350 fTreeFragment->data.onGlobalTrigger
2351 = containsGlobalTrigger(waveformTimestamp, fragInfo.nSamplesPerChannel);
2352 assignEventInfo(fTreeFragment->data);
2353 fTreeFragment->tree->Fill();
2360 (artdaq::Fragment
const& fragment) -> BoardID_t
2362 return static_cast<BoardID_t
>(fragment.fragmentID());
2368 (artdaq::Fragment
const& artdaqFragment)
const -> FragmentInfo_t
2373 artdaq::Fragment::fragment_id_t
const fragment_id
2375 artdaq::Fragment::timestamp_t
const fragmentTimestamp
2376 = artdaqFragment.timestamp();
2377 std::uint16_t
const* data_begin =
reinterpret_cast<std::uint16_t
const*
>
2378 (artdaqFragment.dataBeginBytes() +
sizeof(sbndaq::CAENV1730EventHeader));
2383 sbndaq::CAENV1730Fragment
const fragment { artdaqFragment };
2384 sbndaq::CAENV1730FragmentMetadata
const& metafrag = *(fragment.Metadata());
2385 sbndaq::CAENV1730EventHeader
const& header = fragment.Event()->Header;
2387 unsigned int const eventCounter = header.eventCounter;
2389 unsigned int const TTT = header.triggerTimeTag;
2391 std::uint16_t
const enabledChannels = header.ChannelMask();
2397 std::size_t
const eventSize = header.eventSize *
sizeof(std::uint32_t);
2399 constexpr std::size_t headerSize =
sizeof(sbndaq::CAENV1730EventHeader);
2401 std::size_t
const sampleDataSize = eventSize - headerSize;
2403 std::size_t
const samplesInFragment = sampleDataSize /
sizeof(std::uint16_t);
2405 std::size_t
const nChannelsPerBoard = metafrag.nChannels;
2406 std::size_t
const nSamplesPerChannel = samplesInFragment / nChannelsPerBoard;
2411 if (fDiagnosticOutput) {
2414 <<
"----> PMT Fragment ID: " << std::hex << fragment_id << std::dec
2415 <<
", size: " << eventSize <<
" B"
2416 <<
", data size: " << samplesInFragment <<
" samples"
2418 <<
" channels/board: " << nChannelsPerBoard
2420 <<
", samples/channel: " << nSamplesPerChannel
2422 <<
" event counter: " << eventCounter
2423 <<
", trigger time tag: " << TTT
2424 <<
", time stamp: " << (fragmentTimestamp / 1
'000'000
'000UL)
2425 << "." << (fragmentTimestamp % 1'000
'000'000UL) <<
" s"
2448 FragmentInfo_t
const& fragInfo,
2449 NeededBoardInfo_t
const& boardInfo,
2450 SplitTimestamp_t triggerTime
2454 std::size_t
const fragment_id = fragInfo.fragmentID;
2455 std::size_t
const eff_fragment_id = effectivePMTboardFragmentID(fragment_id);
2457 if (!fChannelMap.hasPMTDigitizerID(eff_fragment_id)) {
2459 <<
"*** PMT could not find channel information for fragment: "
2465 if (fTTTresetEverySecond)
2466 return fragmentWaveformTimestampFromTTT(fragInfo, boardInfo, triggerTime);
2468 return fragmentWaveformTimestampOnTrigger(fragInfo, boardInfo, triggerTime);
2475 FragmentInfo_t
const& ,
2476 NeededBoardInfo_t
const& boardInfo,
2480 nanoseconds
const preTriggerTime = boardInfo.preTriggerTime;
2481 nanoseconds
const PMTtriggerDelay = boardInfo.PMTtriggerDelay;
2483 auto const timestamp = fNominalTriggerTime - PMTtriggerDelay - preTriggerTime;
2485 <<
"' has data starting at electronics time " << timestamp
2486 <<
" = " << fNominalTriggerTime
2487 <<
" - " << PMTtriggerDelay <<
" - " << preTriggerTime
2496 FragmentInfo_t
const& fragInfo,
2497 NeededBoardInfo_t
const& boardInfo,
2498 SplitTimestamp_t triggerTime
2515 using namespace util::quantities::time_literals;
2525 unsigned int const triggerTimeNS = triggerTime.split.nanoseconds;
2528 unsigned int const TTT = fragInfo.TTT * 8;
2558 int fragmentRelTime =
static_cast<int>(TTT) - triggerTimeNS;
2559 if (TTT > triggerTimeNS + 500
'000'000U) {
2572 fragmentRelTime -= 1
'000'000
'000;
2574 else if (TTT + 500'000
'000U < triggerTimeNS) { // 0.5 seconds
2576 * case when global trigger arrives just before the boundary of the second
2577 * (e.g. global trigger at 1620'284
'028 seconds + 999'800
'000 nanoseconds)
2578 * and this fragment was tagged after that crossing (e.g. 0.5 milliseconds
2579 * later, at 1620'284
'029 seconds + 300'000
nanoseconds, i.e. with a
2580 * trigger tag around 300
'000 because of the pulse-per-second reset);
2581 * in this example, the fragment is 0.5 ms late: 500'000 nanoseconds =
2582 * 300
'000 (TTT) + 1'000
'000'000 (
second step) - 999
'800'000 (glob. trigger)
2583 *
and the plain difference,
2584 * 300
'000 (TTT) - 999'800
'000 (glob. trigger) = -999'500
'000,
2585 * must be corrected by adding a whole second:
2587 fragmentRelTime += 1'000
'000'000;
2590 waveformTime += nanoseconds::castFrom(fragmentRelTime);
2595 waveformTime -= fragInfo.nSamplesPerChannel *
fOpticalTick;
2610 waveformTime += boardInfo.TTTresetDelay;
2612 mf::LogTrace(
fLogCategory) <<
"V1730 board '" << boardInfo.name
2613 <<
"' has data starting at electronics time " << waveformTime
2614 <<
" = " << fNominalTriggerTime <<
" (global trigger)"
2615 <<
" + " <<
nanoseconds(fragmentRelTime) <<
" (TTT - global trigger)"
2616 <<
" - " << (fragInfo.nSamplesPerChannel *
fOpticalTick) <<
" (buffer size)"
2617 <<
" + " << boardInfo.TTTresetDelay <<
" (reset delay)"
2620 return waveformTime;
2628 (artdaq::Fragment::fragment_id_t fragment_id)
const -> NeededBoardInfo_t
2631 assert(fBoardInfoLookup);
2641 = fBoardInfoLookup->findBoardInfo(fragment_id);
2643 if (fRequireKnownBoards) {
2644 cet::exception
e(
"DaqDecoderICARUSPMT");
2645 e <<
"Input fragment has ID " << fragment_id
2646 <<
" which has no associated board information (`BoardSetup`";
2647 if (!hasPMTconfiguration()) e <<
" + `.FragmentID`";
2652 assert(boardInfo->
fragmentID == fragment_id);
2653 assert(boardInfo->
setup);
2656 return fetchNeededBoardInfo(boardInfo, fragment_id);
2662 std::set<std::string>
names;
2665 :
setup.channelSettings
2677 (std::vector<daq::details::BoardSetup_t>
const& allBoardSetup)
const
2682 std::unordered_map<raw::Channel_t, unsigned int> assignedChannels;
2683 bool hasDuplicates =
false;
2686 :
setup.channelSettings
2691 if (++assignedChannels[chSetup.
channelID] > 1) hasDuplicates =
true;
2694 if (!hasDuplicates)
return;
2696 art::Exception e { art::errors::Configuration };
2697 e <<
"Some channel ID are specified in multiple board special channel setup:";
2698 for (
auto [ channelID, entries ]: assignedChannels) {
2699 if (entries <= 1)
continue;
2700 e <<
"\n - channel ID 0x" << std::hex << channelID << std::dec <<
": "
2701 << entries <<
" times";
2710 (artdaq::Fragment
const& fragment)
2712 sbndaq::CAENV1730Fragment
const V1730fragment { fragment };
2713 sbndaq::CAENV1730EventHeader
const header = V1730fragment.Event()->Header;
2715 unsigned int TTT { header.triggerTimeTag };
2723 (std::vector<ProtoWaveform_t>& waveforms)
const
2725 auto byChannelThenTime = []
2726 (ProtoWaveform_t
const&
left, ProtoWaveform_t
const&
right)
2728 return (left.waveform.ChannelNumber() !=
right.waveform.ChannelNumber())
2729 ? left.waveform.ChannelNumber() <
right.waveform.ChannelNumber()
2730 : left.waveform.TimeStamp() <
right.waveform.TimeStamp();
2733 std::sort(waveforms.begin(), waveforms.end(), byChannelThenTime);
2740 (std::vector<std::string>
const& treeNames)
2743 auto findTree = [](std::string
const&
name)
2745 return static_cast<DataTrees
>(
2747 std::find(TreeNames.begin(), TreeNames.end(),
name))
2751 for (std::string
const&
name: treeNames) {
2752 switch (findTree(
name)) {
2753 case DataTrees::Fragments: initFragmentsTree();
break;
2756 throw cet::exception(
"DaqDecoderICARUSPMT")
2757 <<
"initTrees(): no data tree supported with name '" <<
name
2767 (TTree& tree, TreeData_EventID_t& data)
2772 tree.Branch(
"run", &data.run);
2773 tree.Branch(
"subrun", &data.subrun);
2774 tree.Branch(
"event", &data.event);
2775 tree.Branch(
"timestamp", &data.timestamp.time,
"timestamp/L");
2783 if (fTreeFragment)
return;
2785 TTree* tree = art::ServiceHandle<art::TFileService>()
2786 ->make<TTree>(
"PMTfragments",
"PMT fragment data");
2788 fTreeFragment = std::make_unique<TreeFragment_t>();
2789 fTreeFragment->tree = tree;
2790 auto& data = fTreeFragment->data;
2792 initEventIDtree(*tree, data);
2794 tree->Branch(
"fragmentID", &data.fragmentID);
2795 tree->Branch(
"fragCount", &data.fragCount);
2796 tree->Branch(
"fragTime", &data.fragTime.time,
"fragTime/L");
2797 tree->Branch(
"fragTimeSec", &data.fragTime.split.seconds);
2798 tree->Branch(
"TTT", &data.TriggerTimeTag,
"TTT/l");
2799 tree->Branch(
"trigger", &data.trigger.time,
"trigger/L");
2800 tree->Branch(
"triggerSec", &data.trigger.split.seconds);
2801 tree->Branch(
"triggerNS", &data.trigger.split.nanoseconds);
2802 tree->Branch(
"relBeamGateNS", &data.relBeamGate,
"relBeamGateNS/I");
2803 tree->Branch(
"waveformTime", &data.waveformTime);
2804 tree->Branch(
"waveformSize", &data.waveformSize);
2805 tree->Branch(
"triggerBits", &data.triggerBits);
2806 tree->Branch(
"gateCount", &data.gateCount);
2807 tree->Branch(
"onGlobal", &data.onGlobalTrigger);
2816 if (!fEventInfo) fEventInfo = std::make_unique<TreeData_EventID_t>();
2822 (TreeData_EventID_t& treeData)
const
2826 treeData = *fEventInfo;
2833 (art::Event
const& event, TreeData_EventID_t& treeData)
const
2835 art::EventID
const&
id =
event.id();
2836 treeData.run =
id.run();
2837 treeData.subrun =
id.subRun();
2838 treeData.event =
id.event();
2840 art::Timestamp
const& timestamp =
event.time();
2842 = {
static_cast<int>(timestamp.timeHigh()), timestamp.timeLow() };
fhicl::Atom< nanoseconds > TriggerDelay
NeededBoardInfo_t fetchNeededBoardInfo(daq::details::BoardInfoLookup::BoardInfo_t const *boardInfo, unsigned int fragmentID) const
Puts together all the needed information for a board.
unsigned int event
Event number.
Definitions of the trigger bits for SBN.
detinfo::DetectorTimings const fDetTimings
Interface to LArSoft configuration for detector timing.
void beginRun(art::Run &run) override
On a new run: cache PMT configuration information.
Information used in decoding from a board.
electronics_time waveformStartTime(ProtoWaveform_t const &wf) const
std::vector< daq::details::BoardSetup_t > const fBoardSetup
All board setup settings.
fhicl::OptionalAtom< unsigned int > FragmentID
std::string boardName
Name (mnemonic) of the board.
void usesEventInfo()
Declares the use of event information.
void endJob() override
Prints a end-of-job message.
fhicl::Atom< std::string > Name
then source grid fermiapp products dune setup_dune_fermiapp sh exit else echo No setup file found exit fi setup
std::array< std::string, static_cast< std::size_t >(DataTrees::N)> TreeNameList_t
fhicl::Atom< nanoseconds > TTTresetDelay
void fillPMTfragmentTree(FragmentInfo_t const &fragInfo, TriggerInfo_t const &triggerInfo, electronics_time waveformTimestamp)
std::vector< DigitizerChannelChannelIDPair > DigitizerChannelChannelIDPairVec
bool const fSurviveExceptions
Whether to "ignore" errors.
NeededBoardInfo_t neededBoardInfo(artdaq::Fragment::fragment_id_t fragment_id) const
Returns the board information for this fragment.
AllChannelSetup_t const & channelSetup() const
void checkBoardSetup(std::vector< daq::details::BoardSetup_t > const &allBoardSetup) const
Throws an exception if the configuration of boards shows errors.
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
void produce(art::Event &event) override
Processes the event.
artdaq::Fragment::fragment_id_t fragmentID
Utility class for fast lookup of board data by fragment ID.
Derivative information of a V1730 readout board.
bool mustSave() const
Whether this channel is requested to be saved.
Data structure for basic event information in simple ROOT trees.
Definition of util::enumerate().
static unsigned int extractTriggerTimeTag(artdaq::Fragment const &fragment)
Extracts the Trigger Time Tag (31+1 bits) value from the fragment.
DataTrees
Enumerate the supported data trees.
microseconds_as<> microseconds
Type of time interval stored in microseconds, in double precision.
std::array< ChannelSetup_t, NBoardChannels > AllChannelSetup_t
artdaq::FragmentPtrs makeFragmentCollectionFromFragment(artdaq::Fragment const &sourceFragment) const
Converts a plain fragment into a fragment collection.
std::vector< ProtoWaveform_t > processFragment(artdaq::Fragment const &artdaqFragment, NeededBoardInfo_t const &boardInfo, TriggerInfo_t const &triggerInfo)
Create waveforms and fills trees for the specified artDAQ fragment.
bool const fRequireKnownBoards
Whether info on all input boards is required.
long int relBeamGate
Beam gate start relative to trigger [ns].
bool mustSkip() const
Whether this channel is requested to be skipped.
bool operator<(const VectorMap< _Key, _Tp, _Compare > &__x, const VectorMap< _Key, _Tp, _Compare > &__y)
Collection of useful information from fragment data.
electronics_time const fNominalTriggerTime
Trigger time as reported by detinfo::DetectorClocks service.
Some helpers for PMT decoder tool.
void sortWaveforms(std::vector< ProtoWaveform_t > &waveforms) const
Sorts in place the specified waveforms in channel order, then in time.
sbn::triggerSourceMask bits
Trigger bits.
electronics_time waveformEndTime(raw::OpDetWaveform const &wf) const
TriggerInfo_t fetchTriggerTimestamp(art::Event const &event) const
Retrieves the global trigger time stamp from the event.
void assignEventInfo(TreeData_EventID_t &treeData) const
Assigns the cached event information to the specified tree data.
std::vector< BoardInfo_t > Database_t
pure virtual base interface for detector clocks
std::set< std::string > getAllInstanceNames() const
Returns all the instance names we will produce.
void checkFragmentType(artdaq::Fragment const &artdaqFragment) const
Throws an exception if artdaqFragment is not of type CAEN1730.
ProtoWaveform_t mergeWaveformGroup(std::vector< ProtoWaveform_t > &allWaveforms, std::vector< std::size_t > const &indices) const
util::ArtHandleTrackerManager< art::Event > fDataCacheRemover
Tracks art data products and removes their cached data on demand.
static AllChannelSetup_t const DefaultChannelSetup
Structure collecting all data for a fragment ROOT tree.
static long long int timestampDiff(std::uint64_t a, std::uint64_t b)
Returns the timestamp difference a - b.
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
unsigned int fragmentID
DAQ fragment ID.
artdaq::Fragment::timestamp_t fragmentTimestamp
Interface to detinfo::DetectorClocks.
nanoseconds PMTtriggerDelay
artdaq::FragmentPtrs makeFragmentCollectionFromContainerFragment(artdaq::Fragment const &sourceFragment) const
Converts a container fragment into a fragment collection.
unsigned int bufferLength
Ticks in each buffer (recordLength).
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
raw::Channel_t channelID
Associated off-line (LArSoft) channel ID.
daq::details::BoardInfoLookup matchBoardConfigurationAndSetup(sbn::PMTconfiguration const *PMTconfig) const
Returns a lookup object with board setup and configuration info.
SplitTimestamp_t time
Time of the trigger (absolute).
electronics_time fragmentWaveformTimestampFromTTT(FragmentInfo_t const &fragInfo, NeededBoardInfo_t const &boardInfo, SplitTimestamp_t triggerTime) const
Returns the timestamp for the waveforms in the specified fragment.
void initEventIDtree(TTree &tree, TreeData_EventID_t &data)
Initializes the event ID part of a tree.
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
std::vector< ProtoWaveform_t > createFragmentWaveforms(FragmentInfo_t const &fragInfo, AllChannelSetup_t const &channelSetup, electronics_time const timeStamp) const
Creates raw::OpDetWaveform objects from the fragment data.
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
Configuration of the V1730 readout board setup.
second seconds
Alias for common language habits.
long int relBeamGateTime
Time of beam gate relative to trigger [ns].
std::vector< ProtoWaveform_t const * > findWaveformsWithNominalTrigger(std::vector< ProtoWaveform_t > const &waveforms) const
Returns pointers to all waveforms including the nominal trigger time.
bool const fDropRawDataAfterUse
Clear fragment data product cache after use.
fhicl::OptionalSequence< fhicl::Table< ChannelSetupConfig > > SpecialChannels
electronics_time fragmentWaveformTimestamp(FragmentInfo_t const &fragInfo, NeededBoardInfo_t const &boardInfo, SplitTimestamp_t triggerTime) const
Returns the timestamp for the waveforms in the specified fragment.
daq::details::BoardSetup_t::AllChannelSetup_t AllChannelSetup_t
Type of setup of all channels in a readout board.
FragmentInfo_t extractFragmentInfo(artdaq::Fragment const &artdaqFragment) const
Extracts useful information from fragment data.
constexpr std::array< std::size_t, geo::vect::dimension< Vector >)> indices()
Returns a sequence of indices valid for a vector of the specified type.
std::vector< art::InputTag > const fInputTags
< List of candidate data products with artDAQ data fragments.
std::optional< daq::details::BoardInfoLookup > fBoardInfoLookup
Find the information on a readout boards by fragment ID.
nanoseconds TTTresetDelay
Special settings for one channel on the board.
std::vector< ProtoWaveform_t > processBoardFragments(artdaq::FragmentPtrs const &artdaqFragment, TriggerInfo_t const &triggerInfo)
Extracts waveforms from the specified fragments from a board.
nanoseconds preTriggerTime
art::EDProducer::Table< Config > Parameters
return match has_match and(match.match_pdg==11 or match.match_pdg==-11)
bool const fDiagnosticOutput
If true will spew endless messages to output.
BEGIN_PROLOG vertical distance to the surface Name
void initFragmentsTree()
Initializes the fragment data tree (fTreeFragment).
unsigned int mergeWaveforms(std::vector< ProtoWaveform_t > &waveforms) const
Information from the configuration of PMT readout.
Test of util::counter and support utilities.
unsigned int run
Run number.
Data structure for trigger time.
std::string const fLogCategory
Message facility category.
nanoseconds const fOpticalTick
Duration of the optical detector readout sampling tick (i.e. 2 ns; hush!).
static constexpr unsigned int NoFragmentID
Special value to mark the absence of fragment ID information.
static bool isChannel(raw::Channel_t channel)
Returns if channel is a valid channel ID.
An interval (duration, length, distance) between two quantity points.
Utility to dump a artDAQ fragment on screen.
Coll::value_type const * binarySearch(Coll const &coll, Key const &key, KeyExtractor &&extractKey)
artdaq::Fragments const & readInputFragments(art::Event const &event) const
Reads the fragments to be processed.
SplitTimestamp_t trigger
Global trigger time.
icarusDB::IICARUSChannelMap const & fChannelMap
Fragment/channel mapping database.
std::optional< art::InputTag > const fTriggerTag
Input tag of the global trigger.
electronics_time waveformStartTime(raw::OpDetWaveform const &wf) const
bool containsGlobalTrigger(raw::OpDetWaveform const &waveform) const
Returns whether waveform includes the tick of the nominal trigger time.
Split_t split
Trigger time in nanoseconds from The Epoch (in components).
Record of information about a readout board.
nanoseconds_as<> nanoseconds
Type of time interval stored in nanoseconds, in double precision.
static const std::vector< std::string > names
Utilities to read interval and point quantity FHiCL configuration.
bool UpdatePMTConfiguration(sbn::PMTconfiguration const *PMTconfig)
Updates the PMT configuration cache. How? Dunno. Placeholder.
electronics_time waveformEndTime(ProtoWaveform_t const &wf) const
bool const fRequireBoardConfig
Whether setup info on all boards is required.
Produces raw::OpDetWaveform from V1730 artDAQ data fragments.
static BoardID_t extractFragmentBoardID(artdaq::Fragment const &fragment)
Extracts the fragment ID (i.e. board ID) from the specified fragment.
details::DumpFragWrap dumpFragment(artdaq::Fragment const &frag)
Dump a artDAQ fragment into an output stream.
std::string category
Category of this channel (will become instance name).
std::string to_string(WindowPattern const &pattern)
DaqDecoderICARUSPMT(Parameters const ¶ms)
Constructor.
bool const fTTTresetEverySecond
Whether V1730 TTT is reset every second.
std::ostream & operator<<(std::ostream &, Binner< T > const &)
process_name sequence::icarus_stage0_EastHits_TPC physics sequence::icarus_stage0_EastHits_TPC physics pathNUMI physics streamNUMI outputs outBNB drop *_ *_ *_DAQ drop *_daqTPCROI_ *_ drop *_decon1droi_ *_ drop *_decon1DroiTPC *_ *_ *outputs outNUMI drop *_ *_ *_DAQ drop *_daqTPCROI_ *_ drop *_decon1droi_ *_ drop *_decon1DroiTPC *_ *_ *physics producers daqPMT DecoderTool RequireBoardConfig
Dimensioned variables representing space or time quantities.
void fillTreeEventID(art::Event const &event, TreeData_EventID_t &treeData) const
Fills the base information of a tree data entry from an art event.
dumpChannel(DaqDecoderICARUSPMT::ProtoWaveform_t const &wf)
A class exposing an upgraded interface of detinfo::DetectorClocksData.
process_name largeant stream1 can override from command line with o or output physics producers generator N
mask_t< triggerSource > triggerSourceMask
Type of mask with triggerSource bits.
bool const fPacketDump
Dump V1730 data.
BoardSetup_t const * setup
Collection of information about the global trigger.
SplitTimestamp_t timestamp
Event timestamp (seconds from the epoch).
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
float postTriggerFrac
Fraction of the waveform after the trigger signal (postPercent).
bool hasChannel() const
Returns if this channel is associated to a off-line channel number.
DaqDecoderICARUSPMT::ProtoWaveform_t const & wf
constexpr SplitTimestamp_t()=default
static constexpr auto NoChannelID
Special value for unassigned channel ID.
void initTrees(std::vector< std::string > const &treeNames)
Initializes all requested data trees.
unsigned int TriggerBits() const
Trigger Bits.
std::optional< art::InputTag > const fPMTconfigTag
Input tag of the PMT configuration.
std::size_t count(Cont const &cont)
artdaq::FragmentPtrs makeFragmentCollection(artdaq::Fragment const &sourceFragment) const
bool hasPMTconfiguration() const
Returns whether PMT configuration information is expected to be available.
Main module configuration.
Tracks handles for cache deletion.
Information of the setup of a V1730 readout board.
std::unique_ptr< TreeFragment_t > fTreeFragment
bool empty(FixedBins< T, C > const &) noexcept
Class containing configuration for PMT readout.
timescale_traits< ElectronicsTimeCategory >::time_point_t electronics_time
A point in time on the electronics time scale.
electronics_time fragmentWaveformTimestampOnTrigger(FragmentInfo_t const &fragInfo, NeededBoardInfo_t const &boardInfo, SplitTimestamp_t triggerTime) const
Returns the timestamp for the waveforms in the specified fragment.
std::unique_ptr< TreeData_EventID_t > fEventInfo
Event ID for trees.
unsigned int subrun
Subrun number.
TimeTrackTreeStorage::TriggerInputSpec_t convert(TimeTrackTreeStorage::Config::TriggerSpecConfig const &config)
Functions to dump the content of binary data chunks to console.
short int BoardID_t
Type used internally to represent board ID.
static std::string name()
Name of this time scale.
std::vector< sbn::V1730Configuration > boards
Configuration of all PMT readout boards.
nanosecond nanoseconds
Alias for common language habits.
static TreeNameList_t const TreeNames
Class containing configuration for a V1730 board.
bool const fSkipWaveforms
Whether to skip waveform decoding.
SplitTimestamp_t fragTime
PMT fragment time stamp.