diff --git a/otsdaq-mu2e-calorimeter/ArtModules/CaloDataVerifier_module.cc b/otsdaq-mu2e-calorimeter/ArtModules/CaloDataVerifier_module.cc index bb02db8..d31940f 100644 --- a/otsdaq-mu2e-calorimeter/ArtModules/CaloDataVerifier_module.cc +++ b/otsdaq-mu2e-calorimeter/ArtModules/CaloDataVerifier_module.cc @@ -49,6 +49,12 @@ namespace mu2e { (static_cast(ewt[2]) << 32); return eventWindow; } + + artdaq::Fragments getFragments(art::Event& event); + void processCaloData(mu2e::DTCEventFragment& eventFragment, std::unique_ptr> const& caloDecoderColl); + + bool checkAndUpdateDTCEWT(const DTCLib::DTC_SubEvent& subevent); + bool checkAndUpdateROCEWT(const DTCLib::DTC_DataBlock& dataBlock); private: @@ -58,6 +64,12 @@ namespace mu2e { bool produceCaloDecoders_; DTCLib::DTC_Subsystem subsystem_; bool isFirstEvent_; + + std::map lastDTCEventWindow; + std::map> lastROCEventWindow; + + size_t nCaloEvents; + size_t nCaloHits; }; } // namespace mu2e @@ -77,6 +89,8 @@ mu2e::CaloDataVerifier::CaloDataVerifier(const art::EDFilter::Table& con if (produceCaloDecoders_) { produces>(); } + + TLOG(TLVL_DEBUG) << "Reading data type " << data_type_; } bool mu2e::CaloDataVerifier::filter(art::Event& event){ @@ -87,6 +101,39 @@ bool mu2e::CaloDataVerifier::filter(art::Event& event){ //Prepare vector of output data decoders std::unique_ptr> caloDecoderColl(new std::vector); + nCaloEvents = 0; + nCaloHits = 0; + + artdaq::Fragments fragments = getFragments(event); + TLOG(TLVL_DEBUG) << "Iterating through " << fragments.size() << " fragments\n"; + for (const auto& frag : fragments) { + mu2e::DTCEventFragment eventFragment(frag); + processCaloData(eventFragment, caloDecoderColl); + } + + TLOG(TLVL_DEBUG) << "[CaloDataVerifier::filter] found " << nCaloEvents << " calo subevents in event" << (int)eventNumber; + TLOG(TLVL_DEBUG) << "[CaloDataVerifier::filter] found " << nCaloHits << " calo hits in event" << (int)eventNumber; + + if (nCaloEvents == 0) { + TLOG(TLVL_WARNING) << "[CaloDataVerifier::filter] found no calo subevents in event" << (int)eventNumber << "!"; + } + if (produceCaloDecoders_) { + event.put(std::move(caloDecoderColl)); + } + + TLOG(TLVL_INFO) << "mu2e::CaloDataVerifier::filter exiting eventNumber=" << (int)eventNumber; + return true; +} + + +bool mu2e::CaloDataVerifier::endRun( art::Run& ) { + return true; +} + + + + +artdaq::Fragments mu2e::CaloDataVerifier::getFragments(art::Event& event){ artdaq::Fragments fragments; artdaq::FragmentPtrs containerFragments; @@ -119,137 +166,168 @@ bool mu2e::CaloDataVerifier::filter(art::Event& event){ } } } + return fragments; +} - size_t nCaloEvents(0); - size_t nCaloHits(0); +void mu2e::CaloDataVerifier::processCaloData(mu2e::DTCEventFragment& eventFragment, std::unique_ptr> const& caloDecoderColl){ - TLOG(TLVL_DEBUG) << "Iterating through " << fragments.size() << " fragments\n"; - for (const auto& frag : fragments) { - mu2e::DTCEventFragment eventFragment(frag); + DTCLib::DTC_Event dtcevent = eventFragment.getData(); + //DTCLib::DTC_EventHeader* eventHeader = dtcevent.GetHeader(); + std::vector subevents = dtcevent.GetSubEvents(); + TLOG(TLVL_DEBUG) << "Found " << subevents.size() << " total subevents\n"; - DTCLib::DTC_Event dtcevent = eventFragment.getData(); - //DTCLib::DTC_EventHeader* eventHeader = dtcevent.GetHeader(); - std::vector subevents = dtcevent.GetSubEvents(); - TLOG(TLVL_DEBUG) << "Found " << subevents.size() << " total subevents\n"; - - auto caloSubEvents = eventFragment.getSubsystemData(subsystem_); - TLOG(TLVL_DEBUG) << "Iterating through " << caloSubEvents.size() << " calorimeter subevents\n"; - for (const auto& subevent : caloSubEvents) { - - // Retrieve the calo DTC header - const DTCLib::DTC_SubEventHeader* caloEvent_header = subevent.GetHeader(); - TLOG(TLVL_DEBUG) << "Calo subevent header:\n" << caloEvent_header->toJson(); - uint64_t dtcID = caloEvent_header->source_dtc_id; - - mu2e::CalorimeterDataDecoder caloDecoder(subevent); - if (produceCaloDecoders_) { - caloDecoderColl->emplace_back(caloDecoder); - } - nCaloEvents++; - - // Iterate over the data blocks (ROCs) - std::vector dataBlocks = subevent.GetDataBlocks(); - uint nROCs = dataBlocks.size(); - TLOG(TLVL_DEBUG) << "Iterating through " << nROCs << " data blocks (ROCs)\n"; - for (uint iroc = 0; iroc < nROCs; iroc++){ - // print the data block header - DTCLib::DTC_DataHeaderPacket* dataHeader = dataBlocks[iroc].GetHeader().get(); - TLOG(TLVL_DEBUG) << dataHeader->toJSON() << std::endl; - - if (data_type_ == 0){ // STANDARD HITS - - auto caloHits = caloDecoder.GetCalorimeterHitData(iroc); - uint nHits = caloHits->size(); - TLOG(TLVL_INFO) << "There are " << nHits << " hits in DTC " << dtcID << " ROC " << iroc << " / " << nROCs << std::endl; - for (uint ihit = 0; ihitat(ihit).first; - std::vector hit_waveform = caloHits->at(ihit).second; - if (hit_waveform.size() == 0){ - TLOG(TLVL_WARNING) << "[CaloDataVerifier::filter] found empty waveform! DTC " << dtcID << " ROC " << iroc << " hit " << ihit - << " BoardID " << hit.BoardID << " ChannelNumber " << hit.ChannelNumber; - } - nCaloHits++; + auto caloSubEvents = eventFragment.getSubsystemData(subsystem_); + TLOG(TLVL_DEBUG) << "Iterating through " << caloSubEvents.size() << " calorimeter subevents\n"; + for (const auto& subevent : caloSubEvents) { + + checkAndUpdateDTCEWT(subevent); + uint64_t dtcID = subevent.GetDTCID(); + + mu2e::CalorimeterDataDecoder caloDecoder(subevent); + if (produceCaloDecoders_) { + caloDecoderColl->emplace_back(subevent); //FIXME: double construction of this calo decoder + } + nCaloEvents++; + // Iterate over the data blocks (ROCs) + std::vector dataBlocks = subevent.GetDataBlocks(); + uint nROCs = dataBlocks.size(); + TLOG(TLVL_DEBUG) << "Iterating through " << nROCs << " data blocks (ROCs)\n"; + for (uint iroc = 0; iroc < nROCs; iroc++){ + + checkAndUpdateROCEWT(dataBlocks[iroc]); + + if (data_type_ == 0){ // STANDARD HITS + + auto caloHits = caloDecoder.GetCalorimeterHitData(iroc); + uint nHits = caloHits->size(); + TLOG(TLVL_INFO) << "There are " << nHits << " hits in DTC " << dtcID << " ROC " << iroc << " / " << nROCs << std::endl; + for (uint ihit = 0; ihitat(ihit).first; + std::vector hit_waveform = caloHits->at(ihit).second; + if (hit_waveform.size() == 0){ + TLOG(TLVL_WARNING) << "[CaloDataVerifier::filter] found empty waveform! DTC " << dtcID << " ROC " << iroc << " hit " << ihit + << " BoardID " << hit.BoardID << " ChannelNumber " << hit.ChannelNumber; } - - } else if (data_type_ == 1){ // DEBUG HITS - - auto caloHits = caloDecoder.GetCalorimeterHitTestData(iroc); - uint nHits = caloHits->size(); - TLOG(TLVL_INFO) << "There are " << nHits << " hits in DTC " << dtcID << " ROC " << iroc << " / " << nROCs << std::endl; - for (uint ihit = 0; ihitat(ihit).first; - std::vector hit_waveform = caloHits->at(ihit).second; - - if (hit_waveform.size() == 0){ - TLOG(TLVL_WARNING) << "[CaloDataVerifier::filter] found empty waveform! DTC " << dtcID << " ROC " << iroc << " hit " << ihit - << " BoardID " << hit.BoardID << " ChannelID " << hit.ChannelID; - } - - nCaloHits++; + nCaloHits++; + } - TLOG(TLVL_DEBUG) - << "Hit " << ihit << " :" << std::endl - << "\tBeginMarker: " << std::hex << hit.BeginMarker << std::dec << std::endl - << "\tBoardID: " << hit.BoardID << std::endl - << "\tChannelID: " << hit.ChannelID << std::endl - << "\tInPayloadEventWindowTag: " << hit.InPayloadEventWindowTag << std::endl - << "\tLastSampleMarker: " << std::hex << hit.LastSampleMarker << std::dec << std::endl - << "\tErrorFlags: " << hit.ErrorFlags << std::endl - << "\tTime: " << hit.Time << std::endl - << "\tIndexOfMaxDigitizerSample: " << hit.IndexOfMaxDigitizerSample << std::endl - << "\tNumberOfSamples: " << hit.NumberOfSamples << std::endl; - - if (metricMan != nullptr){ - TLOG(TLVL_DEBUG) << "[CaloDataVerifier::filter] sending hit metrics to Grafana..." << std::endl; - metricMan->sendMetric("BoardID", hit.BoardID, "Board ID number", - metrics_reporting_level_, artdaq::MetricMode::LastPoint); - metricMan->sendMetric("ChannelID", hit.ChannelID, "Channel ID number", - metrics_reporting_level_, artdaq::MetricMode::LastPoint); - metricMan->sendMetric("NumberOfSamples", hit.NumberOfSamples, "Number of samples", - metrics_reporting_level_, artdaq::MetricMode::LastPoint); - } - + } else if (data_type_ == 1){ // DEBUG HITS + auto caloHits = caloDecoder.GetCalorimeterHitTestData(iroc); + uint nHits = caloHits->size(); + TLOG(TLVL_INFO) << "There are " << nHits << " hits in DTC " << dtcID << " ROC " << iroc << " / " << nROCs << std::endl; + for (uint ihit = 0; ihitat(ihit).first; + std::vector hit_waveform = caloHits->at(ihit).second; + if (hit_waveform.size() == 0){ + TLOG(TLVL_WARNING) << "[CaloDataVerifier::filter] found empty waveform! DTC " << dtcID << " ROC " << iroc << " hit " << ihit + << " BoardID " << hit.BoardID << " ChannelID " << hit.ChannelID; } - + nCaloHits++; + + TLOG(TLVL_DEBUG) + << "Hit " << ihit << " :" << std::endl + << "\tBeginMarker: " << std::hex << hit.BeginMarker << std::dec << std::endl + << "\tBoardID: " << hit.BoardID << std::endl + << "\tChannelID: " << hit.ChannelID << std::endl + << "\tInPayloadEventWindowTag: " << hit.InPayloadEventWindowTag << std::endl + << "\tLastSampleMarker: " << std::hex << hit.LastSampleMarker << std::dec << std::endl + << "\tErrorFlags: " << hit.ErrorFlags << std::endl + << "\tTime: " << hit.Time << std::endl + << "\tIndexOfMaxDigitizerSample: " << hit.IndexOfMaxDigitizerSample << std::endl + << "\tNumberOfSamples: " << hit.NumberOfSamples << std::endl + << "\twaveform size: " << hit_waveform.size() << std::endl; + + std::stringstream ss_wf; + for (auto sample : hit_waveform) ss_wf << sample << " "; + TLOG(TLVL_DEBUG) << "Waveform:\n" << ss_wf.str(); + if (metricMan != nullptr){ - metricMan->sendMetric("nHits", int(nHits), "Hits", + TLOG(TLVL_DEBUG) << "[CaloDataVerifier::filter] sending hit metrics to Grafana..." << std::endl; + metricMan->sendMetric("BoardID", hit.BoardID, "Board ID number", + metrics_reporting_level_, artdaq::MetricMode::LastPoint); + metricMan->sendMetric("ChannelID", hit.ChannelID, "Channel ID number", + metrics_reporting_level_, artdaq::MetricMode::LastPoint); + metricMan->sendMetric("NumberOfSamples", hit.NumberOfSamples, "Number of samples", metrics_reporting_level_, artdaq::MetricMode::LastPoint); } } - } - - if (metricMan != nullptr){ - metricMan->sendMetric("nSubEvents", caloSubEvents.size(), "Subevents", - metrics_reporting_level_, artdaq::MetricMode::LastPoint); + if (metricMan != nullptr){ + metricMan->sendMetric("nHits", int(nHits), "Hits", + metrics_reporting_level_, artdaq::MetricMode::LastPoint); + } + } else if (data_type_ == 2){ // COUNTERS + auto caloHits = caloDecoder.GetCalorimeterCountersData(iroc); + uint nHits = caloHits->size(); + TLOG(TLVL_INFO) << "There are " << nHits << " hits in DTC " << dtcID << " ROC " << iroc << " / " << nROCs << std::endl; + for (uint ihit = 0; ihitat(ihit).first; + std::vector hit_counters = caloHits->at(ihit).second; + if (hit_counters.size() == 0){ + TLOG(TLVL_WARNING) << "[CaloDataVerifier::filter] found empty counters! DTC " << dtcID << " ROC " << iroc << " hit " << ihit; + } + nCaloHits++; + + TLOG(TLVL_DEBUG) + << "Hit " << ihit << " :" << std::endl + << "\numberOfCounters: " << hit.numberOfCounters << std::endl + << "\tcounters size: " << hit_counters.size() << std::endl; + + std::stringstream ss_wf; + for (auto sample : hit_counters) ss_wf << sample << " "; + TLOG(TLVL_DEBUG) << "Counters:\n" << ss_wf.str(); + + if (metricMan != nullptr){ + TLOG(TLVL_DEBUG) << "[CaloDataVerifier::filter] sending hit metrics to Grafana..." << std::endl; + metricMan->sendMetric("NumberOfCounters", hit.numberOfCounters, "Number of counters", + metrics_reporting_level_, artdaq::MetricMode::LastPoint); + } + } + if (metricMan != nullptr){ + metricMan->sendMetric("nHits", int(nHits), "Hits", + metrics_reporting_level_, artdaq::MetricMode::LastPoint); + } } } - - TLOG(TLVL_DEBUG) << "[CaloDataVerifier::filter] found " << nCaloEvents << " calo subevents" << std::endl; - TLOG(TLVL_DEBUG) << "[CaloDataVerifier::filter] found " << nCaloHits << " calo hits" << std::endl; - - if (nCaloEvents == 0) { - TLOG(TLVL_WARNING) << "[CaloDataVerifier::filter] found no calo subevents!" << std::endl; - } - - TLOG(TLVL_INFO) << "mu2e::CaloDataVerifier::filter exiting eventNumber=" - << (int)(event.event()) << " / timestamp=" << (int)eventNumber << std::endl; - if (metricMan != nullptr){ - TLOG(TLVL_DEBUG) << "Sending nFragments metric!\n"; - metricMan->sendMetric("nFragments", fragments.size(), "Fragments", - metrics_reporting_level_, artdaq::MetricMode::LastPoint); + metricMan->sendMetric("nSubEvents", caloSubEvents.size(), "Subevents", + metrics_reporting_level_, artdaq::MetricMode::LastPoint); } - } - - if (produceCaloDecoders_) { - event.put(std::move(caloDecoderColl)); +} + +bool mu2e::CaloDataVerifier::checkAndUpdateDTCEWT(const DTCLib::DTC_SubEvent& subevent){ + uint64_t dtcID = subevent.GetDTCID(); + long int dtcEWT = subevent.GetEventWindowTag().GetEventWindowTag(true); + TLOG(TLVL_DEBUG) << "DTC: " << dtcID << " - Current EWT: " << dtcEWT << " - Previous EWT: " << lastDTCEventWindow[dtcID]; + if (lastDTCEventWindow.find(dtcEWT) != lastDTCEventWindow.end() && dtcEWT != lastDTCEventWindow[dtcID] + 1) { + TLOG(TLVL_ERROR) << "Error in the event window (DTC)!\n" + << "current: " << dtcEWT + << " previous: " << lastDTCEventWindow[dtcID] + << "\nCurrent DTC HEADER: " << subevent.GetHeader()->toJson(); + lastDTCEventWindow[dtcID] = dtcEWT; + return false; } + lastDTCEventWindow[dtcID] = dtcEWT; return true; } - -bool mu2e::CaloDataVerifier::endRun( art::Run& ) { +bool mu2e::CaloDataVerifier::checkAndUpdateROCEWT(const DTCLib::DTC_DataBlock& dataBlock){ + + // print the data block header + DTCLib::DTC_DataHeaderPacket* rocHeader = dataBlock.GetHeader().get(); + uint64_t dtcID = rocHeader->GetID(); + uint64_t rocID = rocHeader->GetLinkID(); + long int rocEWT = rocHeader->GetEventWindowTag().GetEventWindowTag(true); + TLOG(TLVL_DEBUG) << "DTC: " << dtcID << " - ROC: " << rocID << " - Current EWT: " << rocEWT << " - Previous EWT: " << lastROCEventWindow[dtcID][rocID]; + if (lastROCEventWindow.find(rocEWT) != lastROCEventWindow.end() && rocEWT != lastROCEventWindow[dtcID][rocID] + 1) { + TLOG(TLVL_ERROR) << "Error in the event window (ROC)!\n" + << "current: " << rocEWT + << " previous: " << lastROCEventWindow[dtcID][rocID] + << "\nCurrent ROC HEADER: " << rocHeader->toJSON(); + lastROCEventWindow[dtcID][rocID] = rocEWT; + return false; + } + lastROCEventWindow[dtcID][rocID] = rocEWT; return true; } diff --git a/test/CaloVerifierFilter_test.fcl b/test/CaloVerifierFilter_test.fcl index 90bf5d1..275669a 100644 --- a/test/CaloVerifierFilter_test.fcl +++ b/test/CaloVerifierFilter_test.fcl @@ -26,6 +26,9 @@ source : { } services : { + + TimeTracker: {} + ArtdaqSharedMemoryServiceInterface: { service_provider: ArtdaqSharedMemoryService waiting_time: 1 @@ -36,6 +39,12 @@ services : { service_provider: ArtdaqFragmentNamingService helper_plugin: Mu2e } + + GeometryService : {inputFile: "Offline/Mu2eG4/geom/geom_common.txt" bFieldFile: "Offline/Mu2eG4/geom/bfgeom_reco_v01.txt" simulatedDetector : {tool_type: "Mu2e"}} + ConditionsService : { conditionsfile : "Offline/ConditionsService/data/conditions_01.txt"} + GlobalConstantsService : {inputFile : "Offline/GlobalConstantsService/data/globalConstants_01.txt"} + DbService : @local::DbEmpty + ProditionsService : @local::Proditions } @@ -45,42 +54,68 @@ physics: { filters: { caloVerifier : { - module_type : CaloDataVerifier - metricsLevel : 2 - subsystemOverride : tracker + module_type : CaloDataVerifier + dataType : 1 + metricsLevel : 2 + subsystemOverride : tracker + produceCaloDecoders : true } } producers : { genFrags : { - module_type : ArtFragmentsFromDTCEvents - diagLevel : 10 + module_type : ArtFragmentsFromDTCEvents + diagLevel : 10 makeCaloFrag : 1 makeTrkFrag : 1 makeCRVFrag : 0 makeSTMFrag : 0 } + + makeCaloHits : { + module_type : CaloHitsFromFragments + caloTag : "caloVerifier" + diagLevel : 1 + digiSampling : 5 + deltaTPulses : 5. + nPEperMeV : 30 + noiseLevelMeV : 0.55 + nSigmaNoise : 4 + # hitEDepMax : 80. + hitEDepMax : 1000. # for testing + hitEDepMin : 0.0 + caphriEDepMax : 5.0 #MeV + caphriEDepMin : 1.0 #MeV + } + + makeCaloReco : { + module_type : CaloRecoFromFragments + caloTag : "caloVerifier" + dataType : 1 + diagLevel : 0 + } } - t1 : [ caloVerifier ] - e1 : [ ] # dump, outfile ] + t1 : [ caloVerifier , makeCaloReco ] + e1 : [ outfile ] # dump, outfile ] trigger_paths : [t1] - end_paths : [e1] + end_paths : [e1] } outputs: { - outfile : { - module_type : RootOutput - fileName : "calo_filter.art" - } + outfile : { + module_type : RootDAQOut + fileName : "calo_filter.art" + outputCommands: [ "drop *", "keep mu2e::CaloDigis_*_*_*" ] + } - dump: { - module_type: FileDumperOutput - wantProductFriendlyClassName: true - onlyIfPresent: true - } + dump: { + module_type: FileDumperOutput + wantProductFriendlyClassName: true + onlyIfPresent: true + } } services.TFileService.fileName : "CaloVerifierFilter_test.root"