From 7ac59bf00f97347e49e1777150d7865fde2851fc Mon Sep 17 00:00:00 2001 From: Pavel Murat Date: Thu, 4 Jan 2024 16:52:55 -0600 Subject: [PATCH 1/5] CMakeLists.txt --- .../ArtModules/TrackerDQM_module.cc | 840 +++++++++++++----- .../ArtModules/TrackerDQM_module.hh | 274 ++++++ 2 files changed, 887 insertions(+), 227 deletions(-) create mode 100644 otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.hh diff --git a/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc b/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc index aa373bd..032d2f2 100644 --- a/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc +++ b/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc @@ -1,268 +1,654 @@ +/////////////////////////////////////////////////////////////////////////////// // Author: E. Croft, adapted from code by S. Middleton // This module (should) produce histograms of data from the straw tracker - -#include -#include - -#include -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" -#include "Offline/TrkHitReco/inc/PeakFit.hh" -#pragma GCC diagnostic pop -#include "Offline/DataProducts/inc/StrawId.hh" -#include "Offline/DataProducts/inc/TrkTypes.hh" - -#include - -#include "art/Framework/Core/EDAnalyzer.h" -#include "art/Framework/Core/ModuleMacros.h" -#include "art/Framework/Principal/Event.h" -#include "art/Framework/Principal/Handle.h" -#include "art_root_io/TFileService.h" -#include "artdaq-core-mu2e/Data/TrackerFragment.hh" -#include "artdaq-core-mu2e/Overlays/DTCEventFragment.hh" -#include "artdaq-core-mu2e/Overlays/FragmentType.hh" -#include "fhiclcpp/types/OptionalAtom.h" -#include "otsdaq-mu2e-dqm/ArtModules/TrackerDQM.h" -#include "otsdaq-mu2e-dqm/ArtModules/TrackerDQMHistoContainer.h" -#include "otsdaq-mu2e/ArtModules/HistoSender.hh" -#include "otsdaq/Macros/CoutMacros.h" -#include "otsdaq/Macros/ProcessorPluginMacros.h" -#include "otsdaq/MessageFacility/MessageFacility.h" -#include "otsdaq/NetworkUtilities/TCPSendClient.h" - -namespace ots { -class TrackerDQM : public art::EDAnalyzer { - public: - struct Config { - using Name = fhicl::Name; - using Comment = fhicl::Comment; - fhicl::Atom port{ - Name("port"), - Comment( - "This parameter sets the port where the histogram will be sent")}; - fhicl::Atom address{ - Name("address"), Comment("This paramter sets the IP address where the " - "histogram will be sent")}; - fhicl::Atom moduleTag{Name("moduleTag"), - Comment("Module tag name")}; - fhicl::Atom fittype { Name( "FitType"), - Comment("Waveform Fit Type")}; - fhicl::Sequence histType{ - Name("histType"), - Comment("This parameter determines which quantity is histogrammed")}; - fhicl::Atom freqDQM{ - Name("freqDQM"), - Comment("Frequency for sending histograms to the data-receiver")}; - fhicl::Atom diag{Name("diagLevel"), Comment("Diagnostic level"), 0}; - }; - - typedef art::EDAnalyzer::Table Parameters; - - explicit TrackerDQM(Parameters const& conf); - - void analyze(art::Event const& event) override; - void beginRun(art::Run const&) override; - void beginJob() override; - void endJob() override; - - void PlotRate(art::Event const& e); - - private: - Config conf_; - int port_; - std::string address_; - std::string moduleTag_; - bool useADCWF_; - std::vector histType_; - int freqDQM_, diagLevel_, evtCounter_; - art::ServiceHandle tfs; - TrackerDQMHistoContainer* pedestal_histos = new TrackerDQMHistoContainer(); - TrackerDQMHistoContainer* panel_histos = new TrackerDQMHistoContainer(); - TrackerDQMHistoContainer* summary_histos = new TrackerDQMHistoContainer(); - HistoSender* histSender_; - bool doPedestalHist_, doPanelHist_; - std::string moduleTag; - void analyze_tracker_(const mu2e::TrackerFragment& cc); -}; -} // namespace ots - -ots::TrackerDQM::TrackerDQM(Parameters const& conf) - : art::EDAnalyzer(conf), - conf_(conf()), - port_(conf().port()), - address_(conf().address()), - moduleTag_(conf().moduleTag()), - useADCWF_(conf().fittype() != mu2e::TrkHitReco::FitType::firmwarepmp ), - histType_(conf().histType()), - freqDQM_(conf().freqDQM()), - diagLevel_(conf().diag()), - evtCounter_(0), - doPedestalHist_(false), - doPanelHist_(false) { - histSender_ = new HistoSender(address_, port_); - - if (diagLevel_ > 0) { - __MOUT__ << "[TrackerDQM::analyze] DQM for " << histType_[0] << std::endl; +/////////////////////////////////////////////////////////////////////////////// +#include "TRACE/tracemf.h" +#define TRACE_NAME "tfm_frontend" + +// #include "otsdaq-mu2e-dqm/ArtModules/TrackerDQM.h" +// #include "otsdaq-mu2e-dqm/ArtModules/TrackerDQMHistoContainer.h" +// #include "otsdaq-mu2e/ArtModules/HistoSender.hh" +// #include "otsdaq/Macros/CoutMacros.h" +// #include "otsdaq/Macros/ProcessorPluginMacros.h" +// #include "otsdaq/MessageFacility/MessageFacility.h" +// #include "otsdaq/NetworkUtilities/TCPSendClient.h" + +#include "TSystem.h" + +#include "otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.hh" + +//----------------------------------------------------------------------------- +unsigned int reverseBits(unsigned int num) { + unsigned int numOfBits = 10; // sizeof(num) * 8; // Number of bits in an unsigned int + + unsigned int reversedNum = 0; + for (unsigned int i = 0; i < numOfBits; ++i) { + if ((num & (1 << i)) != 0) + reversedNum |= 1 << ((numOfBits - 1) - i); } - for (std::string name : histType_) { - if (name == "pedestals") { - doPedestalHist_ = true; - } - if (name == "panels") { - doPanelHist_ = true; + return reversedNum; +} + +//----------------------------------------------------------------------------- +unsigned int correctedTDC(unsigned int TDC) { + uint32_t corrected_tdc = ((TDC & 0xFFFF00) + (0xFF - (TDC & 0xFF))); + return corrected_tdc; +} + +//----------------------------------------------------------------------------- +// NWords : the number of short words +//----------------------------------------------------------------------------- +void TrackerDQM::printFragment(const artdaq::Fragment* Frag, int NWords) { +//----------------------------------------------------------------------------- +// print fragments in HEX, for the tracker, the data has to be in 2-byte words +//----------------------------------------------------------------------------- + ushort* buf = (ushort*) (Frag->dataBegin()); + + int loc = 0; + + for (int i=0; iBookSummaryHistos(tfs, "PanelOccupancy", 220, 0, 220); - summary_histos->BookSummaryHistos(tfs, "PlaneOccupancy", 40, 0, 40); - - if (doPedestalHist_) { - for (int plane = 0; plane < mu2e::StrawId::_nplanes; plane++) { - for (int panel = 0; panel < mu2e::StrawId::_npanels; panel++) { - for (int straw = 0; straw < mu2e::StrawId::_nstraws; straw++) { - pedestal_histos->BookHistos(tfs, - "Pedestal_" + std::to_string(plane) + - "_" + std::to_string(panel) + "_" + - std::to_string(straw), - plane, panel, straw); - } - } - } +//----------------------------------------------------------------------------- +TrackerDQM::TrackerDQM(art::EDAnalyzer::Table const& conf) : + art::EDAnalyzer (conf), + + _diagLevel (conf().diagLevel ()), + _minNBytes (conf().minNBytes ()), + _maxNBytes (conf().maxNBytes ()), + _dataHeaderOffset(conf().dataHeaderOffset()), + _activeLinks (conf().activeLinks ()), + _refChCal (conf().refChCal ()), + _refChHV (conf().refChHV ()), + _dumpDTCRegisters(conf().dumpDTCRegisters()), + _analyzeFragments(conf().analyzeFragments()), + _maxFragmentSize (conf().maxFragmentSize ()), + _pulserFrequency (conf().pulserFrequency ()) +{ + // conf_ (conf()), + // histType_ (conf().histType ()), + //diagLevel_ (conf().diag ()), + +//----------------------------------------------------------------------------- +// for now, assume only one station, but implement data structures handling +// full tracker +//----------------------------------------------------------------------------- + _station = 0; + _plane = 0; +} + +//----------------------------------------------------------------------------- +// I : channel number +//----------------------------------------------------------------------------- +void TrackerDQM::book_channel_histograms(art::TFileDirectory* Dir, int RunNumber, ChannelHist_t* Hist, int I) { + + Hist->nhits = Dir->make(Form("ch_%02i_nhits" ,I),Form("run %06i: ch %02i nhits" ,RunNumber,I), 100, 0., 100.); + + Hist->time[0] = Dir->make(Form("ch_%02i_time0" ,I),Form("run %06i: ch %02i time[0]",RunNumber,I),1000, 0., 100.); // us + Hist->time[1] = Dir->make(Form("ch_%02i_time1" ,I),Form("run %06i: ch %02i time[0]",RunNumber,I),1000, 0., 100.); // us + + Hist->t0 [0] = Dir->make(Form("ch_%02i_t0_0" ,I),Form("run %06i: ch %02i t0[0] ",RunNumber,I),1000,-20., 80.); // ns + Hist->t0 [1] = Dir->make(Form("ch_%02i_t0_1" ,I),Form("run %06i: ch %02i t0[1] ",RunNumber,I),1000,-20., 80.); // ns + + Hist->t1 [0] = Dir->make(Form("ch_%02i_t1_0" ,I),Form("run %06i: ch %02i t1[0] ",RunNumber,I),1000,-20., 80.); // ns + Hist->t1 [1] = Dir->make(Form("ch_%02i_t1_1" ,I),Form("run %06i: ch %02i t1[1] ",RunNumber,I),1000,-20., 80.); // ns + + Hist->tot [0] = Dir->make(Form("ch_%02i_tot0" ,I),Form("run %06i: ch %02i tot[0]" ,RunNumber,I), 100, 0., 100.); + Hist->tot [1] = Dir->make(Form("ch_%02i_tot1" ,I),Form("run %06i: ch %02i tot[1]" ,RunNumber,I), 100, 0., 100.); + Hist->pmp = Dir->make(Form("ch_%02i_pmp" ,I),Form("run %06i: ch %02i pmp" ,RunNumber,I), 100, 0., 10.); + Hist->dt0 = Dir->make(Form("ch_%02i_dt0" ,I),Form("run %06i: ch %02i T0(i+1)-T0(i)",RunNumber,I) ,50000, 0.,50); + Hist->dt1 = Dir->make(Form("ch_%02i_dt1" ,I),Form("run %06i: ch %02i T1(i+1)-T1(i)",RunNumber,I) ,50000, 0.,50); + Hist->dt2 = Dir->make(Form("ch_%02i_dt2" ,I),Form("run %06i: ch %02i T2(i+1)-T2(i)",RunNumber,I) ,50000, 0.,50); + Hist->dt0r = Dir->make(Form("ch_%02i_dt0r_0" ,I),Form("run %06i: ch %02i T0(ich,0)-T0(ref,0)[0]",RunNumber,I),20000,-10.,10); + Hist->dt1r = Dir->make(Form("ch_%02i_dt1r_0" ,I),Form("run %06i: ch %02i T1(ich,0)-T1(ref,0)[0]",RunNumber,I),20000,-10.,10); + + for (int j=0; jwf[j] = Dir->make(Form("h_wf_ch_%02i_%i",I,j),Form("run %06i: ch [%02i][%i] waveform",RunNumber,I,j),20, 0.,20.); } +} - if (doPanelHist_) { - for (int plane = 0; plane < mu2e::StrawId::_nplanes; plane++) { - for (int panel = 0; panel < mu2e::StrawId::_npanels; panel++) { - std::string hName = - "Panel_" + std::to_string(plane) + "_" + std::to_string(panel); - panel_histos->BookHistos(tfs, hName, plane, panel, -1); - } - } + +//----------------------------------------------------------------------------- +void TrackerDQM::book_roc_histograms(art::TFileDirectory* Dir, int RunNumber, RocHist_t* Hist, int Link) { + Hist->nbytes = Dir->make("nbytes" , Form("run %06i: n bytes" ,RunNumber),10000, 0., 10000.); + Hist->npackets = Dir->make("npackets", Form("run %06i: n packets" ,RunNumber), 1000, 0., 1000.); + Hist->nhits = Dir->make("nhits" , Form("run %06i: n hits" ,RunNumber), 300, 0., 300.); + Hist->valid = Dir->make("valid" , Form("run %06i: valid" ,RunNumber), 2, 0., 2.); + + Hist->nh_vs_ch = Dir->make("nh_vs_ch" , Form("run %06i: nh vs ch" ,RunNumber), 100,0.,100., 10,0,10); + Hist->nh_vs_adc1 = Dir->make("nh_vs_adc1", Form("run %06i: nh vs adc" ,RunNumber), 100,0.,100., 10,0,10); + + Hist->dt0r_vs_ch = Dir->make("dt0r_vs_ch_0", Form("run %06i: dt0r vs ch[0]",RunNumber), 100,0.,100.,2500,-25,25); + Hist->dt1r_vs_ch = Dir->make("dt1r_vs_ch_0", Form("run %06i: dt1r vs ch[0]",RunNumber), 100,0.,100.,2500,-25,25); + + Hist->dt0r01 = Dir->make("dt0r01", Form("run %06i: dt0r01" ,RunNumber), 40000,-20000,20000); + Hist->dt1r01 = Dir->make("dt1r01", Form("run %06i: dt1r01" ,RunNumber), 40000,-20000,20000); + + Hist->nhits_vs_ich = Dir->make("nh_vs_ich" , Form("run %06i: nh vs ich" ,RunNumber), 100, 0., 100.); + Hist->nhits_vs_adc[0] = Dir->make("nh_vs_adc_0", Form("run %06i: nh vs adc_0",RunNumber), 100, 0., 100.); + Hist->nhits_vs_adc[1] = Dir->make("nh_vs_adc_1", Form("run %06i: nh vs adc_1",RunNumber), 100, 0., 100.); + + Hist->dt0rc_vs_ch[0] = Dir->make("dt0rc_vs_ch_0", Form("run %06i: dt0rc vs ch[0], ns",RunNumber), 100,0.,100.,1000,-10,10); + Hist->dt0rc_vs_ch[1] = Dir->make("dt0rc_vs_ch_1", Form("run %06i: dt0rc vs ch[1], ns",RunNumber), 100,0.,100.,1000,-10,10); + + Hist->dt1rc_vs_ch[0] = Dir->make("dt1rc_vs_ch_0", Form("run %06i: dt1rc vs ch[0], ns",RunNumber), 100,0.,100.,1000,-10,10); + Hist->dt1rc_vs_ch[1] = Dir->make("dt1rc_vs_ch_1", Form("run %06i: dt1rc vs ch[1], ns",RunNumber), 100,0.,100.,1000,-10,10); + + Hist->dt0rc_vs_adc[0] = Dir->make("dt0rc_vs_adc_0", Form("run %06i: dt0rc vs adc[0], ns",RunNumber), 100,0.,100.,1000,-10,10); + Hist->dt0rc_vs_adc[1] = Dir->make("dt0rc_vs_adc_1", Form("run %06i: dt0rc vs adc[1], ns",RunNumber), 100,0.,100.,1000,-10,10); + + Hist->dt1rc_vs_adc[0] = Dir->make("dt1rc_vs_adc_0", Form("run %06i: dt1rc vs adc[0], ns",RunNumber), 100,0.,100.,1000,-10,10); + Hist->dt1rc_vs_adc[1] = Dir->make("dt1rc_vs_adc_1", Form("run %06i: dt1rc vs adc[1], ns",RunNumber), 100,0.,100.,1000,-10,10); + + for (int i=0; imkdir(Form("ch_%02i",i)); + book_channel_histograms(&chan_dir,RunNumber,&Hist->channel[i],i); } } -void ots::TrackerDQM::analyze(art::Event const& event) { - ++evtCounter_; - auto fragmentHandles = event.getMany>(); +//----------------------------------------------------------------------------- +void TrackerDQM::book_event_histograms(art::TFileDirectory* Dir, int RunNumber, EventHist_t* Hist) { + Hist->nhits = Dir->make("nhits" , Form("run %06i: nhits total" ,RunNumber), 1000, 0., 1000.); + Hist->nbtot = Dir->make("nbtot" , Form("run %06i: nbytes total" ,RunNumber), 1000, 0., 100000.); + Hist->nfrag = Dir->make("nfrag" , Form("run %06i: n fragments" ,RunNumber), 100, 0., 100.); + Hist->fsize = Dir->make("fsize" , Form("run %06i: fragment size",RunNumber), 1000, 0., 100000.); + Hist->error = Dir->make("error" , Form("run %06i: error code" ,RunNumber), 10, 0., 10.); + Hist->valid = Dir->make("valid" , Form("run %06i: valid code" ,RunNumber), 100, 0., 100.); +} - for (const auto& handle : fragmentHandles) { - if (!handle.isValid() || handle->empty()) { - continue; - } +//----------------------------------------------------------------------------- +void TrackerDQM::book_histograms(int RunNumber) { + art::ServiceHandle tfs; + + TLOG(TLVL_INFO) << "starting"; - for (auto frag : *handle) { - analyze_tracker_(frag); - } + art::TFileDirectory top_dir = tfs->mkdir("trk"); + + book_event_histograms(&top_dir,RunNumber,&_Hist.event); + + int station = 0; + int plane = 0; + + for (int i=0; i<_nActiveLinks; i++) { + int link = _activeLinks[i]; + art::TFileDirectory roc_dir = top_dir.mkdir(Form("roc_%i",link)); + book_roc_histograms(&roc_dir,RunNumber,&_Hist.roc[station][plane][link],link); } + + TLOG(TLVL_INFO) << Form("pointer to the module: 0x%8p\n",(void*) this); } -void ots::TrackerDQM::analyze_tracker_(const mu2e::TrackerFragment& cc) { - for (size_t curBlockIdx = 0; curBlockIdx < cc.block_count(); - curBlockIdx++) { // iterate over straws - auto block_data = cc.dataAtBlockIndex(curBlockIdx); - if (block_data == nullptr) { - mf::LogError("TrackerDQM") << "Unable to retrieve header from block " - << curBlockIdx << "!" << std::endl; - continue; - } - auto hdr = block_data->GetHeader(); - if (hdr->GetPacketCount() > 0) { - auto trkDatas = cc.GetTrackerData(curBlockIdx, useADCWF_); - if (trkDatas.empty()) { - mf::LogError("TrackerDQM") - << "Error retrieving Tracker data from DataBlock " << curBlockIdx - << "!"; - continue; - } +//----------------------------------------------------------------------------- +void TrackerDQM::beginJob() { + TLOG(TLVL_INFO) << "starting"; + + int tmp_argc(2); + char** tmp_argv; + + tmp_argv = new char*[2]; + tmp_argv[0] = new char[100]; + tmp_argv[1] = new char[100]; + + strcpy(tmp_argv[0],"-b"); + strcpy(tmp_argv[1],Form("--web=server:%d",_port)); + + _app = new TApplication("TrackerDQM", &tmp_argc, tmp_argv); + + // app->Run() + // app_->Run(true); + delete [] tmp_argv; + + _canvas[0] = new TCanvas("canvas_000"); + _canvas[1] = new TCanvas("canvas_001"); + +} - for (auto& trkData : trkDatas) { - mu2e::StrawId sid(trkData.first->StrawIndex); - // mu2e::TrkTypes::TDCValues tdc = { - // static_cast(trkData.first->TDC0()), - // static_cast(trkData.first->TDC1()) }; - // mu2e::TrkTypes::TOTValues tot = { trkData.first->TOT0, - // trkData.first->TOT1 }; - mu2e::TrkTypes::ADCWaveform adcs(trkData.second.begin(), - trkData.second.end()); - summary_fill(summary_histos, sid); - - for (std::string name : histType_) { - if (name == "pedestals") { - pedestal_fill(pedestal_histos, pedestal_est(adcs), "Pedestal", sid); - } else if (name == "panels") { - panel_fill(panel_histos, "Panel", sid); - } else { - __MOUT_ERR__ << "Unrecognized histogram type" << std::endl; - } +//----------------------------------------------------------------------------- +void TrackerDQM::endJob() { + delete _canvas[0]; + delete _canvas[1]; +} + +//----------------------------------------------------------------------------- +void TrackerDQM::beginRun(const art::Run& aRun) { + int rn = aRun.run(); + + if (_initialized != 0) return; + _initialized = 1; + + book_histograms(rn); +} + +//----------------------------------------------------------------------------- +// in the end of the run need to save histograms - will figure that out +//----------------------------------------------------------------------------- +void TrackerDQM::endRun(const art::Run& aRun) { + // int rn = aRun.run(); + + _initialized = 0; +} + +// //----------------------------------------------------------------------------- +// void TrackerDQM::fill_channel_histograms(ChannelHist_t* Hist, ChannelData_t* Data) { +// Hist->nhits->Fill(Data->nhits); +// } + +//----------------------------------------------------------------------------- + void TrackerDQM::fill_roc_histograms(RocHist_t* Hist, RocData_t* Rd) { + + Hist->nbytes->Fill (Rd->nbytes); + Hist->npackets->Fill(Rd->npackets); + Hist->nhits->Fill (Rd->nhits); + Hist->valid->Fill (Rd->valid); + + Hist->dt0r01->Fill (Rd->dt0r01); + Hist->dt1r01->Fill (Rd->dt1r01); + +//----------------------------------------------------------------------------- +// fill channel histograms +//----------------------------------------------------------------------------- + for (int ich=0; ichchannel[ich]; + ChannelHist_t* hch = &Hist->channel[ich]; + + int fpga = _adc_index_1[ich] / 48; + + hch->nhits->Fill(chd->nhits); + hch->dt0r->Fill(chd->dt0r); + hch->dt1r->Fill(chd->dt1r); + + Hist->dt0r_vs_ch->Fill(ich,chd->dt0r); + Hist->dt1r_vs_ch->Fill(ich,chd->dt1r); + + Hist->dt0rc_vs_ch[fpga]->Fill(ich,chd->dt0r_c); + Hist->dt1rc_vs_ch[fpga]->Fill(ich,chd->dt1r_c); + + int iadc = _adc_index_1[ich]; + Hist->dt0rc_vs_adc[fpga]->Fill(iadc,chd->dt0r_c); + Hist->dt1rc_vs_adc[fpga]->Fill(iadc,chd->dt1r_c); +//----------------------------------------------------------------------------- +// there are hits in this channel +//----------------------------------------------------------------------------- + for (int ih=0; ihnhits; ih++) { + mu2e::TrackerDataDecoder::TrackerDataPacket* hit = chd->hit[ih]; + + uint32_t corr_tdc0 = correctedTDC(hit->TDC0()); + uint32_t corr_tdc1 = correctedTDC(hit->TDC1()); + + hch->time[0]->Fill(corr_tdc0*_tdc_bin); // in us + hch->time[1]->Fill(corr_tdc1*_tdc_bin); // in us + + hch->t0 [0]->Fill(corr_tdc0*_tdc_bin_ns); + hch->t0 [1]->Fill(corr_tdc1*_tdc_bin_ns); + + hch->t1 [0]->Fill(_timeWindow-corr_tdc0*_tdc_bin_ns); + hch->t1 [1]->Fill(_timeWindow-corr_tdc1*_tdc_bin_ns); + + hch->tot [0]->Fill(hit->TOT0); + hch->tot [1]->Fill(hit->TOT1); + hch->pmp ->Fill(hit->PMP); +//----------------------------------------------------------------------------- +// waveforms in a given channel +//----------------------------------------------------------------------------- + uint16_t adc[15]; + + adc[ 0] = reverseBits(hit->ADC00); + adc[ 1] = reverseBits(hit->ADC01A + (hit->ADC01B << 6)); + adc[ 2] = reverseBits(hit->ADC02); + + mu2e::TrackerDataDecoder::TrackerADCPacket* ahit = (mu2e::TrackerDataDecoder::TrackerADCPacket*) ((uint16_t*)hit+6); + + adc[ 3] = reverseBits(ahit->ADC0); + adc[ 4] = reverseBits(ahit->ADC1A + (ahit->ADC1B << 6)); + adc[ 5] = reverseBits(ahit->ADC2); + adc[ 6] = reverseBits(ahit->ADC3); + adc[ 7] = reverseBits(ahit->ADC4A + (ahit->ADC4B << 6)); + adc[ 8] = reverseBits(ahit->ADC5); + adc[ 9] = reverseBits(ahit->ADC6); + adc[10] = reverseBits(ahit->ADC7A + (ahit->ADC7B << 6)); + adc[11] = reverseBits(ahit->ADC5); + adc[12] = reverseBits(ahit->ADC6); + adc[13] = reverseBits(ahit->ADC10A + (ahit->ADC10B << 6)); + adc[14] = reverseBits(ahit->ADC11); + + Hist->channel[ich].wf[ih]->Reset(); + for (int is=0; is<15; is++) { + Hist->channel[ich].wf[ih]->Fill(is,adc[is]); } } +//----------------------------------------------------------------------------- +// time distance between the two sequential hits - need at least two +//----------------------------------------------------------------------------- + for (int ih=1; ihnhits; ih++) { + int corr_tdc0_ih = (int) correctedTDC(chd->hit[ih ]->TDC0()); + int corr_tdc1_ih = (int) correctedTDC(chd->hit[ih ]->TDC1()); + int corr_tdc0_ih1 = (int) correctedTDC(chd->hit[ih-1]->TDC0()); + int corr_tdc1_ih1 = (int) correctedTDC(chd->hit[ih-1]->TDC1()); + + double dt0 = (corr_tdc0_ih-corr_tdc0_ih1)*_tdc_bin; + double dt1 = (corr_tdc1_ih-corr_tdc1_ih1)*_tdc_bin; + double dt2 = (dt0+dt1)/2; + + Hist->channel[ich].dt0->Fill(dt0); + Hist->channel[ich].dt1->Fill(dt1); + Hist->channel[ich].dt2->Fill(dt2); + } } +//----------------------------------------------------------------------------- +// + for (int ich=0; ichchannel[ich].nhits; + // number of hits in a channel vs the channel number + Hist->nh_vs_ch->Fill(ich,nh); + Hist->nh_vs_adc1->Fill(ind_1,nh); + + for (int ihit=0; ihitnhits_vs_ich->Fill(ich); + Hist->nhits_vs_adc[0]->Fill(ind_0); + Hist->nhits_vs_adc[1]->Fill(ind_1); + } + } + } - if (evtCounter_ % freqDQM_ != 0) return; +//----------------------------------------------------------------------------- +void TrackerDQM::fill_event_histograms(EventHist_t* Hist, EventData_t* Data) { + + Hist->nbtot->Fill(Data->nbtot); + Hist->nhits->Fill(Data->nhtot); + Hist->nfrag->Fill(Data->nfrag); - if (diagLevel_ > 0) { - __MOUT__ << "[TrackerDQM::analyze] preparing the BUFFER..." << std::endl; + for (int i=0; infrag; i++) { + int fsize = Data->fragments[i].nbytes; + Hist->fsize->Fill(fsize); } +} + +//----------------------------------------------------------------------------- +// fill_roc_histograms also fills the channel histograms +// if in error, only histogram the error code +//----------------------------------------------------------------------------- +int TrackerDQM::fill_histograms() { - // send a packet AND reset the histograms - std::map> hists_to_send; + _Hist.event.error->Fill(_event_data.error); + _Hist.event.valid->Fill(_event_data.valid); + + if (_event_data.error != 0) return -1; + + fill_event_histograms(&_Hist.event,&_event_data); + + for (int ir=0; ir<_nActiveLinks; ir++) { + int link = _activeLinks[ir]; + fill_roc_histograms(&_Hist.roc[_station][_plane][link],&_event_data.rdata[_station][_plane][link]); + } + return 0; +} - // send the summary hists - for (size_t i = 0; i < summary_histos->histograms.size(); i++) { - __MOUT__ << "[TrackerDQM::analyze] collecting summary histogram " - << summary_histos->histograms[i]._Hist << std::endl; - hists_to_send[moduleTag_ + "_summary"].push_back( - (TH1*)summary_histos->histograms[i]._Hist->Clone()); - summary_histos->histograms[i]._Hist->Reset(); +//----------------------------------------------------------------------------- +// a fragment may have multiple ROC blocks +//----------------------------------------------------------------------------- +void TrackerDQM::analyze_fragment(const art::Event& Evt, const artdaq::Fragment* Fragment) { + + short* fdata = (short*) Fragment->dataBegin(); + + _event_data.fragments.push_back(FragmentData_t()); + FragmentData_t* fdt = &_event_data.fragments.back(); +//----------------------------------------------------------------------------- +// fragment size is specified in longs and includes service data, don't use +//----------------------------------------------------------------------------- + fdt->nbytes = fdata[0]; + if (fdata[0] > _maxFragmentSize) { + _event_data.error = 3; + TLOG(TLVL_ERROR) << Form("event %6i:%8i:%8i : ERROR:%i in %s: fdt->nbytes= %i, BAIL OUT\n", + Evt.run(),Evt.subRun(),Evt.event(),_event_data.error,__func__,fdt->nbytes); + return; } +//----------------------------------------------------------------------------- +// start handling the ROC data +//----------------------------------------------------------------------------- + short* first_address = fdata+_dataHeaderOffset; // offset is specified in 2-byte words + short* last_address = fdata+fdt->nbytes/2; // + + while (first_address < last_address) { + + DtcDataHeaderPacket_t* dh = (DtcDataHeaderPacket_t*) first_address; + int link = dh->ROCID; +//----------------------------------------------------------------------------- +// check link number +//----------------------------------------------------------------------------- + int found = 0; + for (int i=0; i<_nActiveLinks; i++) { + if (_activeLinks[i] == link) { + found = 1; + break; + } + } + + if (found == 0) { + _event_data.error = 4; + TLOG(TLVL_ERROR) << Form("event %6i:%8i:%8i : ERROR:%i in %s: link=%i, BAIL OUT\n", + Evt.run(),Evt.subRun(),Evt.event(),_event_data.error,__func__,link); + return; + } - for (std::string name : histType_) { - if (diagLevel_ > 0) { - __MOUT__ << "[TrackerDQM::analyze] collecting histograms from the block: " - << name << std::endl; + RocData_t* rd = &_event_data.rdata[_station][_plane][link]; +//----------------------------------------------------------------------------- +// for a given FPGA, a reference channel is the first channel in the readout order +//----------------------------------------------------------------------------- + ChannelData_t* ref_ch[2]; + + ref_ch[0] = &rd->channel[_referenceChannel[link][0]]; + ref_ch[1] = &rd->channel[_referenceChannel[link][1]]; + + rd->nbytes = dh->byteCount; + rd->npackets = dh->nPackets; + rd->nhits = dh->nPackets/2; // printf("nhits : %3i\n",nhits); + rd->valid = dh->valid; + rd->dt0r01 = -1.e12; + rd->dt1r01 = -1.e12; + + _event_data.nhtot += rd->nhits; + _event_data.valid += dh->valid*10; + + for (int i=0; ichannel[i].nhits = 0; } - if (name == "pedestals") { - // prepare the vector of histograms - for (size_t i = 0; i < pedestal_histos->histograms.size(); i++) { - hists_to_send[moduleTag_ + "_" + name + "/plane_" + - std::to_string(pedestal_histos->histograms[i].plane) + - "/panel_" + - std::to_string(pedestal_histos->histograms[i].panel)] - .push_back((TH1*)pedestal_histos->histograms[i]._Hist->Clone()); - pedestal_histos->histograms[i]._Hist->Reset(); + + for (int ihit=0; ihitnhits; ihit++) { +//----------------------------------------------------------------------------- +// first packet, 16 bytes, or 8 ushort's is the data header packet +//----------------------------------------------------------------------------- + mu2e::TrackerDataDecoder::TrackerDataPacket* hit ; + hit = (mu2e::TrackerDataDecoder::TrackerDataPacket*) (fdata+ihit*0x10+_dataHeaderOffset+0x08); + int ich = hit->StrawIndex; + + if (ich > 128) ich = ich-128; + + if (ich > 95) { + _event_data.error = 1; + TLOG(TLVL_ERROR) << Form("event %6i:%8i:%8i : ERROR:%i in %s: link = %i ich = %i, BAIL OUT\n", + Evt.run(),Evt.subRun(),Evt.event(),_event_data.error,__func__,link,ich); + return; } - } else if (name == "panels") { - if (diagLevel_ > 0) { - __MOUT__ << Form( - "[%s::analyze] preparing the collection of hists for ", - moduleTag_.data()) - << name << " histograms" << std::endl; + + ChannelData_t* chd = &rd->channel[ich]; + + int nh = chd->nhits; + if (nh >= kMaxNHitsPerChannel) { + _event_data.error = 2; + TLOG(TLVL_ERROR) << Form("event %6i:%8i:%8i : ERROR:%i in %s: link = %i ich = %i, N(hits) >= %i BAIL OUT\n", + Evt.run(),Evt.subRun(),Evt.event(),_event_data.error,__func__,link,ich,kMaxNHitsPerChannel); + return; } - // prepare the vector of histograms - __MOUT__ << Form("[%sDQM::analyze] N hists = ", moduleTag_.data()) - << panel_histos->histograms.size() << std::endl; - for (size_t i = 0; i < panel_histos->histograms.size(); i++) { - std::string refName = moduleTag_ + "_" + name + "/plane_" + - std::to_string(panel_histos->histograms[i].plane); - hists_to_send[refName].push_back( - (TH1*)panel_histos->histograms[i]._Hist->Clone()); - panel_histos->histograms[i]._Hist->Reset(); + + chd->hit[nh] = hit; + chd->nhits += 1; + } +//----------------------------------------------------------------------------- +// hits in all channels counted +// time difference between a channel and a reference channel +//----------------------------------------------------------------------------- + for (int i=0; ichannel[i]; + + int nh = chd->nhits; + int fpga = _adc_index_1[i] / 48; + + ChannelData_t* rch = ref_ch[fpga]; +//----------------------------------------------------------------------------- +// in most cases, the number of hits in the reference channel should be greater +// than the number of channels in any other channel of a given FPGA +//----------------------------------------------------------------------------- + int iref = _referenceChannel[link][fpga]; + int nhr = rd->channel[iref].nhits; + if ((nhr > 0) and (nh > 0)) { +//----------------------------------------------------------------------------- +// at least one hit in both reference and test channels +//----------------------------------------------------------------------------- + int t0r = correctedTDC(rch->hit[0]->TDC0()); + int t1r = correctedTDC(rch->hit[0]->TDC1()); + int t0 = correctedTDC(chd->hit[0]->TDC0()); + int t1 = correctedTDC(chd->hit[0]->TDC1()); + + float dt_over_2(_dt/2); + + chd->dt0r = (t0-t0r)*_tdc_bin_ns; // convert to ns + + chd->dt0r_c = chd->dt0r; + if (chd->dt0r > dt_over_2/2) chd->dt0r_c = chd->dt0r + _gen_offset[i] - _dt; + if (chd->dt0r < -dt_over_2/2) chd->dt0r_c = chd->dt0r + _gen_offset[i]; + + chd->dt1r = (t1-t1r)*_tdc_bin_ns; // convert to ns + + chd->dt1r_c = chd->dt1r; + if (chd->dt1r > dt_over_2/2) chd->dt1r_c = chd->dt1r + _gen_offset[i] - _dt; + if (chd->dt1r < -dt_over_2/2) chd->dt1r_c = chd->dt1r + _gen_offset[i]; } } +//----------------------------------------------------------------------------- +// time offset between the two pulsers for the same ROC +//----------------------------------------------------------------------------- + if ((rd->ref_ch[0]->nhits > 0) and (rd->ref_ch[1]->nhits > 0)) { + int t0r0 = correctedTDC(rd->ref_ch[0]->hit[0]->TDC0()); + int t1r0 = correctedTDC(rd->ref_ch[0]->hit[0]->TDC1()); + + int t0r1 = correctedTDC(rd->ref_ch[1]->hit[0]->TDC0()); + int t1r1 = correctedTDC(rd->ref_ch[1]->hit[0]->TDC1()); + + rd->dt0r01 = (t0r0-t0r1)*_tdc_bin_ns; // convert to ns + rd->dt1r01 = (t1r0-t1r1)*_tdc_bin_ns; // convert to ns + } +//----------------------------------------------------------------------------- +// address in 2-byte words (N(data packets)+data header packet) +//----------------------------------------------------------------------------- + first_address += (dh->nPackets + 1)*8; } - - histSender_->sendHistograms(hists_to_send); } -void ots::TrackerDQM::endJob() {} +//-------------------------------------------------------------------------------- +// assume that we only have tracker fragment(s) +//----------------------------------------------------------------------------- +void TrackerDQM::analyze(const art::Event& event) { + + _event_data.nbtot = 0; + _event_data.nhtot = 0; + _event_data.nfrag = 0; + _event_data.error = 0; + _event_data.valid = 0; + + _event_data.fragments.clear(); + + // for (int i=0; i<100; i++) _nwf[i] = 0; + +//----------------------------------------------------------------------------- +// first get all fragments, select Tracker ones +//----------------------------------------------------------------------------- + auto handle = event.getValidHandle >("daq:TRK"); +//----------------------------------------------------------------------------- +// calculate the fragment size manually - big thank you to designers (: +//----------------------------------------------------------------------------- + int ifrag = 0; + + for (const artdaq::Fragment& frag : *handle) { + ushort* buf = (ushort*) (frag.dataBegin()); + int nbytes = buf[0]; + int fsize = frag.sizeBytes(); + + if (nbytes < 2) { + _event_data.error = 5; + TLOG(TLVL_ERROR) << Form("event %6i:%8i:%8i : ERROR:%i in %s: nbytes >= %i BAIL OUT\n", + event.run(),event.subRun(),event.event(),_event_data.error, + __func__,nbytes); + } + + _event_data.nfrag += 1; + _event_data.nbtot += nbytes; // including artdaq part + + if ((_event_data.error == 0) and _analyzeFragments) analyze_fragment(event,&frag); + + if (_diagLevel > 2) { + printf("%s: ---------- TRK fragment # %3i nbytes: %5i fsize: %5i\n",__func__,ifrag,nbytes,fsize); + printFragment(&frag,nbytes/2); + } + ifrag++; + } +//----------------------------------------------------------------------------- +// proxy for event histograms +//----------------------------------------------------------------------------- + if (_diagLevel > 1) { + if ((_event_data.nbtot >= _minNBytes) and (_event_data.nbtot <= _maxNBytes)) { + TLOG(TLVL_INFO) << Form(" Run : %5i subrun: %5i event: %8i nfrag: %3i nbytes: %5i\n", + event.run(),event.subRun(),event.event(), _event_data.nfrag, _event_data.nbtot); + } + } +//----------------------------------------------------------------------------- +// go into interactive mode, +// fInteractiveMode = 0 : do not stop +// fInteractiveMode = 1 : stop after each event (event display mode) +// fInteractiveMode = 2 : stop only in the end of run, till '.q' is pressed +//----------------------------------------------------------------------------- +// TModule::analyze(event); +//----------------------------------------------------------------------------- +// event data un(re)packed , fill histograms +//----------------------------------------------------------------------------- + if (_analyzeFragments != 0) { + fill_histograms(); + } +//----------------------------------------------------------------------------- +// DTC registers +//----------------------------------------------------------------------------- + if (_dumpDTCRegisters) { + auto h = event.getValidHandle>("daq:TRKDTC"); + + for (const artdaq::Fragment& frag : *h) { + int *buf = (int*) (frag.dataBegin()); + int nreg = buf[0]; + int fsize = frag.sizeBytes(); + printf("%s: -------- DTC registers dump n(reg)=%5i size: %5i\n",__func__,nreg,fsize); + printFragment(&frag,2+4*nreg); + } + } + + gSystem->ProcessEvents(); +} -void ots::TrackerDQM::beginRun(const art::Run& run) {} -DEFINE_ART_MODULE(ots::TrackerDQM) +DEFINE_ART_MODULE(TrackerDQM) diff --git a/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.hh b/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.hh new file mode 100644 index 0000000..1b0c9b6 --- /dev/null +++ b/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.hh @@ -0,0 +1,274 @@ +#ifndef __TrackerDQM_module_hh__ +#define __TrackerDQM_module_hh__ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#pragma GCC diagnostic pop + +#include "art/Framework/Core/EDAnalyzer.h" +#include "art/Framework/Core/ModuleMacros.h" +#include "art/Framework/Principal/Event.h" +#include "art/Framework/Principal/Handle.h" +#include "art_root_io/TFileService.h" + +#include "fhiclcpp/types/OptionalAtom.h" + +#include "TBufferFile.h" +#include "TH1.h" +#include "TH2.h" +#include "TCanvas.h" +#include "TApplication.h" + +#include "Offline/RecoDataProducts/inc/StrawDigi.hh" +#include "Offline/TrkHitReco/inc/PeakFit.hh" +#include "Offline/DataProducts/inc/StrawId.hh" +#include "Offline/DataProducts/inc/TrkTypes.hh" + +#include "artdaq-core/Data/Fragment.hh" + +#include "artdaq-core-mu2e/Data/TrackerDataDecoder.hh" +#include "artdaq-core-mu2e/Overlays/DTCEventFragment.hh" +#include "artdaq-core-mu2e/Overlays/FragmentType.hh" + +#include "otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.hh" + +//----------------------------------------------------------------------------- +class TrackerDQM : public art::EDAnalyzer { + struct Config { + using Name = fhicl::Name; + using Comment = fhicl::Comment; + + fhicl::Atom diagLevel {Name("diagLevel" ) , Comment("diag level" ) }; + fhicl::Atom minNBytes {Name("minNBytes" ) , Comment("min N(bytes)" ) }; + fhicl::Atom maxNBytes {Name("maxNBytes" ) , Comment("max N(bytes)" ) }; + fhicl::Atom dataHeaderOffset {Name("dataheaderOffset" ) , Comment("data header offset" ) }; + fhicl::Sequence activeLinks {Name("activeLinks" ) , Comment("active Links" ) }; + fhicl::Sequence refChCal {Name("refChCal" ) , Comment("reference channel CAL side" ) }; + fhicl::Sequence refChHV {Name("refChHV" ) , Comment("reference channel HV side" ) }; + fhicl::Atom dumpDTCRegisters {Name("dumpDTCRegisters" ) , Comment("1:dumpDTCRegisters" ) }; + fhicl::Atom analyzeFragments {Name("analyzeFragments" ) , Comment("1:analyzeFragments" ) }; + fhicl::Atom maxFragmentSize {Name("maxFragmentSize" ) , Comment("max fragment size" ) }; + fhicl::Atom pulserFrequency {Name("pulserFrequency" ) , Comment("pulser frequency" ) }; + fhicl::Atom port {Name("port" ) , Comment("port" ) }; + }; + + // TODO use constants from StrawID + enum { + kNStations = 18, + kNPlanesPerStation = 2, + kNPanelsPerPlane = 6, + kNChannels = 96, + kMaxNLinks = 6, + kMaxNHitsPerChannel = 20 + }; + +//----------------------------------------------------------------------------- +// per-channel histograms +//----------------------------------------------------------------------------- + struct ChannelHist_t { + TH1F* nhits; + TH1F* time[2]; + TH1F* t0 [2]; // early times in ns + TH1F* t1 [2]; // late times in ns + TH1F* tot [2]; + TH1F* pmp; + TH1F* dt0; // T0 distance between the two consequtive pulses + TH1F* dt1; // T1 distance between the two consequtive pulses + TH1F* dt2; // T2 = (dt1+dt2)/2 + TH1F* dt0r; // T0(ich,0)-T0(ref,0) + TH1F* dt1r; // T1(ich,0)-distance between the two pulses (if more than one) + TH1F* wf[kMaxNHitsPerChannel]; + }; + +//----------------------------------------------------------------------------- +// per-event histograms +//----------------------------------------------------------------------------- + struct EventHist_t { + TH1F* nbtot; + TH1F* nfrag; + TH1F* nhits; + TH1F* fsize; + TH1F* error; + TH1F* valid; + }; + +//----------------------------------------------------------------------------- +// per-ROC histograms (or per-panel) histograms +//----------------------------------------------------------------------------- + struct RocHist_t { + TH1F* nbytes; + TH1F* npackets; + TH1F* nhits; + TH1F* valid; + TH2F* nh_vs_ch; + TH2F* nh_vs_adc1; + + TH2F* dt0r_vs_ch; + TH2F* dt1r_vs_ch; + // time difference between the two reference channels, + // each TDC separately + TH1F* dt0r01; + TH1F* dt1r01; + + TH2F* dt0rc_vs_ch[2]; + TH2F* dt1rc_vs_ch[2]; + + TH2F* dt0rc_vs_adc[2]; + TH2F* dt1rc_vs_adc[2]; + + TH1F* nhits_vs_ich; + TH1F* nhits_vs_adc[2]; + + ChannelHist_t channel[kNChannels]; + }; + + + struct DtcDMAPacket_t { // 2 16-byte words + uint16_t byteCount : 16; ///< Byte count of current block + uint8_t subsystemID : 4; ///< Hop count + uint16_t packetType : 4; ///< Packet type DTC_PacketType + uint16_t ROCID : 3; ///< Link identifier of packet DTC_LinkID + uint16_t unused : 4; + bool valid : 1; ///< Whether the DTC believes the packet to be valid + }; + + struct DtcDataHeaderPacket_t : public DtcDMAPacket_t { // 8 16-byte words in total + uint16_t nPackets : 11; + uint16_t unused : 5; + uint16_t eventTag[3]; // DTC_EventWindowTag + uint8_t status; // DTC_DataStatus + uint8_t version; + uint8_t DTCID; + uint8_t EVBMode; + }; + + struct DtcDataBlock_t : public DtcDataHeaderPacket_t { + uint16_t hitData[10000]; + }; + +//----------------------------------------------------------------------------- +// forgetting, for now, about multiple DTC's +//----------------------------------------------------------------------------- + struct Hist_t { + EventHist_t event; + RocHist_t roc[kNStations][kNPlanesPerStation][kNPanelsPerPlane]; + } _Hist; + + + struct ChannelData_t { + int nhits; + float dt0r; // time dist btw this channel and an FPGA reference channel, TDC0, ns + float dt1r; // time dist btw this channel and an FPGA reference channel, TDC1, ns + float dt0r_c; // the same, corrected for the FPGA-specific generator time offset + float dt1r_c; + + mu2e::TrackerDataDecoder::TrackerDataPacket* hit[kMaxNHitsPerChannel]; + }; + + struct RocData_t { + int size; + int nhits; + int nbytes; + int npackets; + int valid; + + ChannelData_t channel[kNChannels]; + ChannelData_t* ref_ch [2]; + + float dt0r01; // time difference between the two reference channels, TDC0, ns + float dt1r01; // time difference between the two reference channels, TDC1, ns + }; + + struct FragmentData_t { + int nbytes; + }; + + struct EventData_t { + int nbtot; // total nbytes + int nhtot; + int nfrag; + int valid; + int error; + RocData_t rdata[kNStations][kNPlanesPerStation][kMaxNLinks]; + + std::vector fragments; + } _event_data; + +//----------------------------------------------------------------------------- +// in reality, this is the fragment data, an event can contain multiple fragments +//----------------------------------------------------------------------------- + DtcDataBlock_t* _trkFragment; +//----------------------------------------------------------------------------- +// talk-to parameters +//----------------------------------------------------------------------------- + int _diagLevel; + int _minNBytes; + int _maxNBytes; + int _dataHeaderOffset; + std::vector _activeLinks; // active links - connected ROCs + std::vector _refChCal; // reference channel on CAL side FPGA + std::vector _refChHV; // reference channel on HV side FPGA + art::InputTag _trkfCollTag; + int _dumpDTCRegisters; + int _analyzeFragments; + int _maxFragmentSize; + int _pulserFrequency; // in kHz, either 60 or 250 + + int _timeWindow; // time window (spacing between the two EWMs for a given run) + int _port; // http://localhost:port serves histograms +//----------------------------------------------------------------------------- +// the rest +//----------------------------------------------------------------------------- + int _nActiveLinks; + int _referenceChannel[kMaxNLinks][2]; + int _station; + int _plane; + + int _adc_index_0 [kNChannels]; // seq num of the channel 'i' in the readout sequence + int _adc_index_1 [kNChannels]; // fixed map, seq num of the channel 'i' in the readout sequence + double _gen_offset [kNChannels]; + + double _freq; // generator frequency, defined by the run number + double _dt; // expected distance between the two pulses + double _tdc_bin; // + double _tdc_bin_ns; // TDC bin, in nanoseconds + int _initialized; // histograms are booked in beginRun, protect ... + + Hist_t _hist; + + art::ServiceHandle tfs; + + TApplication* _app; + TCanvas* _canvas[100]; + +public: + + explicit TrackerDQM(art::EDAnalyzer::Table const& conf); + + void analyze (art::Event const& anEvent) override; + void beginJob() override; + void beginRun(art::Run const& aRun ) override; + void endJob () override; + void endRun (art::Run const& aRun ) override; + + + void analyze_fragment (const art::Event& e, const artdaq::Fragment* Fragment); + + void book_channel_histograms(art::TFileDirectory* Dir, int RunNumber, ChannelHist_t* Hist, int Ich); + void book_event_histograms (art::TFileDirectory* Dir, int RunNumber, EventHist_t* Hist); + void book_roc_histograms (art::TFileDirectory* Dir, int RunNumber, RocHist_t* Hist, int Link); + void book_histograms (int RunNumber); + + // void fill_channel_histograms(ChannelHist_t* Hist, ChannelData_t* Data); + void fill_event_histograms (EventHist_t* Hist, EventData_t* Data); + void fill_roc_histograms (RocHist_t* Hist, RocData_t* Data); + + // returns -1 if in trouble + int fill_histograms (); + + // NWords: number of 2-byte words + void printFragment (const artdaq::Fragment* Fragment, int NWords); + +}; + +#endif From 20adb9533b6ef9b344759ed9c028f96b69647dfe Mon Sep 17 00:00:00 2001 From: Pavel Murat Date: Thu, 4 Jan 2024 16:53:46 -0600 Subject: [PATCH 2/5] major overhaul --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 39606df..c8b00ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,8 @@ cet_set_compiler_flags(DIAGS VIGILANT #cet_report_compiler_flags() # these are minimum required versions, not the actual product versions -find_package(otsdaq_mu2e 1.02.00 REQUIRED) +find_package(otsdaq_mu2e 1.02.00 REQUIRED) +find_package(artdaq_core_mu2e 2.01.02 REQUIRED) #find_package(art_root_io 1.10.01 REQUIRED) From ca0d4853a2fe38863f7462ec2126fd2b6c33fd26 Mon Sep 17 00:00:00 2001 From: Mu2E Date: Mon, 8 Jan 2024 22:46:31 -0600 Subject: [PATCH 3/5] use ROOT web-based graphics --- .../ArtModules/TrackerDQM_module.cc | 104 +++++++++++++++--- .../ArtModules/TrackerDQM_module.hh | 3 +- 2 files changed, 93 insertions(+), 14 deletions(-) diff --git a/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc b/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc index 032d2f2..00be7d4 100644 --- a/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc +++ b/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc @@ -3,15 +3,7 @@ // This module (should) produce histograms of data from the straw tracker /////////////////////////////////////////////////////////////////////////////// #include "TRACE/tracemf.h" -#define TRACE_NAME "tfm_frontend" - -// #include "otsdaq-mu2e-dqm/ArtModules/TrackerDQM.h" -// #include "otsdaq-mu2e-dqm/ArtModules/TrackerDQMHistoContainer.h" -// #include "otsdaq-mu2e/ArtModules/HistoSender.hh" -// #include "otsdaq/Macros/CoutMacros.h" -// #include "otsdaq/Macros/ProcessorPluginMacros.h" -// #include "otsdaq/MessageFacility/MessageFacility.h" -// #include "otsdaq/NetworkUtilities/TCPSendClient.h" +#define TRACE_NAME "TrackerDQM" #include "TSystem.h" @@ -77,7 +69,8 @@ TrackerDQM::TrackerDQM(art::EDAnalyzer::Table const& conf) : _dumpDTCRegisters(conf().dumpDTCRegisters()), _analyzeFragments(conf().analyzeFragments()), _maxFragmentSize (conf().maxFragmentSize ()), - _pulserFrequency (conf().pulserFrequency ()) + _pulserFrequency (conf().pulserFrequency ()), + _port (conf().port ()) { // conf_ (conf()), // histType_ (conf().histType ()), @@ -89,6 +82,85 @@ TrackerDQM::TrackerDQM(art::EDAnalyzer::Table const& conf) : //----------------------------------------------------------------------------- _station = 0; _plane = 0; + + double f0(31.29e6); // 31.29 MHz + + _timeWindow = conf().timeWindow()*25.; // in ns + + if (_pulserFrequency == 60) _freq = f0/(pow(2,9)+1); // ~ 60 kHz + else if (_pulserFrequency == 250) _freq = f0/(pow(2,7)+1); // ~250 kHz + + _dt = 1/_freq*1.e9; // in ns +//------------------------------------------------------------------------------ +// default map, Richie says TS1 may have an old firmware with some bugs +//----------------------------------------------------------------------------- + int adc_index_0[96] = { + 91, 85, 79, 73, 67, 61, 55, 49, + 43, 37, 31, 25, 19, 13, 7, 1, + 90, 84, 78, 72, 66, 60, 54, 48, + + 42, 36, 30, 24, 18, 12, 6, 0, + 93, 87, 81, 75, 69, 63, 57, 51, + 45, 39, 33, 27, 21, 15, 9, 3, + + 44, 38, 32, 26, 20, 14, 8, 2, + 92, 86, 80, 74, 68, 62, 56, 50, + 47, 41, 35, 29, 23, 17, 11, 5, + + 95, 89, 83, 77, 71, 65, 59, 53, + 46, 40, 34, 28, 22, 16, 10, 4, + 94, 88, 82, 76, 70, 64, 58, 52 + }; +//----------------------------------------------------------------------------- +// TS1: compared to _0, swap lanes 3 and 4, and in the new lane3 swap lines 1 and 3 +//----------------------------------------------------------------------------- + int adc_index_1[96] = { + 91, 85, 79, 73, 67, 61, 55, 49, + 43, 37, 31, 25, 19, 13, 7, 1, + 90, 84, 78, 72, 66, 60, 54, 48, + + 42, 36, 30, 24, 18, 12, 6, 0, + 93, 87, 81, 75, 69, 63, 57, 51, + 45, 39, 33, 27, 21, 15, 9, 3, + + 94, 88, 82, 76, 70, 64, 58, 52, + 46, 40, 34, 28, 22, 16, 10, 4, + 95, 89, 83, 77, 71, 65, 59, 53, + + 44, 38, 32, 26, 20, 14, 8, 2, + 92, 86, 80, 74, 68, 62, 56, 50, + 47, 41, 35, 29, 23, 17, 11, 5 + }; + + + for (int i=0; i<96; i++) { + _adc_index_0[adc_index_0[i]] = i; + _adc_index_1[adc_index_1[i]] = i; + } + +//----------------------------------------------------------------------------- +// initialize reference channels, at this point use channels 91 and 94 for all +// ROC's (the readout order is defined in firmware and is the same for all channels) +//----------------------------------------------------------------------------- + _nActiveLinks = _activeLinks.size(); + + for (int roc=0; rocnbytes = fdata[0]; + TLOG(TLVL_DEBUG) << "fragment size: " << fdt->nbytes; + if (fdata[0] > _maxFragmentSize) { _event_data.error = 3; - TLOG(TLVL_ERROR) << Form("event %6i:%8i:%8i : ERROR:%i in %s: fdt->nbytes= %i, BAIL OUT\n", + TLOG(TLVL_ERROR) << Form("run:subrun:event %6i:%8i:%8i : ERROR:%i in %s: fdt->nbytes= %i, BAIL OUT\n", Evt.run(),Evt.subRun(),Evt.event(),_event_data.error,__func__,fdt->nbytes); return; } @@ -427,10 +501,14 @@ void TrackerDQM::analyze_fragment(const art::Event& Evt, const artdaq::Fragment* short* first_address = fdata+_dataHeaderOffset; // offset is specified in 2-byte words short* last_address = fdata+fdt->nbytes/2; // + TLOG(TLVL_DEBUG) << "first_address, last_address: " << first_address << " " << last_address; + while (first_address < last_address) { DtcDataHeaderPacket_t* dh = (DtcDataHeaderPacket_t*) first_address; int link = dh->ROCID; + + TLOG(TLVL_DEBUG) << "(" << __LINE__ << ") link:" << link ; //----------------------------------------------------------------------------- // check link number //----------------------------------------------------------------------------- @@ -444,8 +522,8 @@ void TrackerDQM::analyze_fragment(const art::Event& Evt, const artdaq::Fragment* if (found == 0) { _event_data.error = 4; - TLOG(TLVL_ERROR) << Form("event %6i:%8i:%8i : ERROR:%i in %s: link=%i, BAIL OUT\n", - Evt.run(),Evt.subRun(),Evt.event(),_event_data.error,__func__,link); + TLOG(TLVL_ERROR) << Form("event %6i:%8i:%8i : ERROR=%i link=%i, BAIL OUT\n", + Evt.run(),Evt.subRun(),Evt.event(),_event_data.error,link); return; } diff --git a/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.hh b/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.hh index 1b0c9b6..a9208fe 100644 --- a/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.hh +++ b/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.hh @@ -41,7 +41,7 @@ class TrackerDQM : public art::EDAnalyzer { fhicl::Atom diagLevel {Name("diagLevel" ) , Comment("diag level" ) }; fhicl::Atom minNBytes {Name("minNBytes" ) , Comment("min N(bytes)" ) }; fhicl::Atom maxNBytes {Name("maxNBytes" ) , Comment("max N(bytes)" ) }; - fhicl::Atom dataHeaderOffset {Name("dataheaderOffset" ) , Comment("data header offset" ) }; + fhicl::Atom dataHeaderOffset {Name("dataHeaderOffset" ) , Comment("data header offset" ) }; fhicl::Sequence activeLinks {Name("activeLinks" ) , Comment("active Links" ) }; fhicl::Sequence refChCal {Name("refChCal" ) , Comment("reference channel CAL side" ) }; fhicl::Sequence refChHV {Name("refChHV" ) , Comment("reference channel HV side" ) }; @@ -50,6 +50,7 @@ class TrackerDQM : public art::EDAnalyzer { fhicl::Atom maxFragmentSize {Name("maxFragmentSize" ) , Comment("max fragment size" ) }; fhicl::Atom pulserFrequency {Name("pulserFrequency" ) , Comment("pulser frequency" ) }; fhicl::Atom port {Name("port" ) , Comment("port" ) }; + fhicl::Atom timeWindow {Name("timeWindow" ) , Comment("time window, 25 ns ticks" ) }; }; // TODO use constants from StrawID From 06c269c55309cd5cdfaae257710ff7bb97b96b58 Mon Sep 17 00:00:00 2001 From: Mu2E Date: Thu, 11 Jan 2024 18:18:58 -0600 Subject: [PATCH 4/5] fixes --- .../ArtModules/TrackerDQM_module.cc | 20 +++++++++++++------ .../ArtModules/TrackerDQM_module.hh | 5 +++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc b/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc index 00be7d4..cc7cdd8 100644 --- a/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc +++ b/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc @@ -251,7 +251,7 @@ void TrackerDQM::book_histograms(int RunNumber) { art::TFileDirectory top_dir = tfs->mkdir("trk"); - book_event_histograms(&top_dir,RunNumber,&_Hist.event); + book_event_histograms(&top_dir,RunNumber,&_hist.event); int station = 0; int plane = 0; @@ -259,7 +259,7 @@ void TrackerDQM::book_histograms(int RunNumber) { for (int i=0; i<_nActiveLinks; i++) { int link = _activeLinks[i]; art::TFileDirectory roc_dir = top_dir.mkdir(Form("roc_%i",link)); - book_roc_histograms(&roc_dir,RunNumber,&_Hist.roc[station][plane][link],link); + book_roc_histograms(&roc_dir,RunNumber,&_hist.roc[station][plane][link],link); } TLOG(TLVL_INFO) << Form("pointer to the module: 0x%8p\n",(void*) this); @@ -288,6 +288,8 @@ void TrackerDQM::beginJob() { _canvas[0] = new TCanvas("canvas_000"); _canvas[1] = new TCanvas("canvas_001"); + _browser = new TBrowser(); + } //----------------------------------------------------------------------------- @@ -304,6 +306,12 @@ void TrackerDQM::beginRun(const art::Run& aRun) { _initialized = 1; book_histograms(rn); + + _canvas[0]->cd(); + _hist.event.nbtot->Draw(); + + _canvas[1]->cd(); + _hist.event.nfrag->Draw(); } //----------------------------------------------------------------------------- @@ -460,16 +468,16 @@ void TrackerDQM::fill_event_histograms(EventHist_t* Hist, EventData_t* Data) { //----------------------------------------------------------------------------- int TrackerDQM::fill_histograms() { - _Hist.event.error->Fill(_event_data.error); - _Hist.event.valid->Fill(_event_data.valid); + _hist.event.error->Fill(_event_data.error); + _hist.event.valid->Fill(_event_data.valid); if (_event_data.error != 0) return -1; - fill_event_histograms(&_Hist.event,&_event_data); + fill_event_histograms(&_hist.event,&_event_data); for (int ir=0; ir<_nActiveLinks; ir++) { int link = _activeLinks[ir]; - fill_roc_histograms(&_Hist.roc[_station][_plane][link],&_event_data.rdata[_station][_plane][link]); + fill_roc_histograms(&_hist.roc[_station][_plane][link],&_event_data.rdata[_station][_plane][link]); } return 0; } diff --git a/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.hh b/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.hh index a9208fe..57dde2a 100644 --- a/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.hh +++ b/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.hh @@ -18,6 +18,7 @@ #include "TH2.h" #include "TCanvas.h" #include "TApplication.h" +#include "TBrowser.h" #include "Offline/RecoDataProducts/inc/StrawDigi.hh" #include "Offline/TrkHitReco/inc/PeakFit.hh" @@ -153,8 +154,7 @@ class TrackerDQM : public art::EDAnalyzer { struct Hist_t { EventHist_t event; RocHist_t roc[kNStations][kNPlanesPerStation][kNPanelsPerPlane]; - } _Hist; - + }; struct ChannelData_t { int nhits; @@ -241,6 +241,7 @@ class TrackerDQM : public art::EDAnalyzer { TApplication* _app; TCanvas* _canvas[100]; + TBrowser* _browser; public: From 02dbc1239928c48a409c1086a4fd83d2e5f35328 Mon Sep 17 00:00:00 2001 From: Mu2E Date: Thu, 11 Jan 2024 21:52:39 -0600 Subject: [PATCH 5/5] - restore TBrowser. In more recent versions it root/ROOT Memory shows all histograms --- otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc b/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc index cc7cdd8..ce587b3 100644 --- a/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc +++ b/otsdaq-mu2e-dqm/ArtModules/TrackerDQM_module.cc @@ -285,11 +285,6 @@ void TrackerDQM::beginJob() { // app_->Run(true); delete [] tmp_argv; - _canvas[0] = new TCanvas("canvas_000"); - _canvas[1] = new TCanvas("canvas_001"); - - _browser = new TBrowser(); - } //----------------------------------------------------------------------------- @@ -305,6 +300,11 @@ void TrackerDQM::beginRun(const art::Run& aRun) { if (_initialized != 0) return; _initialized = 1; + _canvas[0] = new TCanvas("canvas_000"); + _canvas[1] = new TCanvas("canvas_001"); + + _browser = new TBrowser(); + book_histograms(rn); _canvas[0]->cd();