diff --git a/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplay.h b/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplay.h index d9c51d0a1ee3b..95e8407fab5ec 100644 --- a/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplay.h +++ b/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplay.h @@ -22,6 +22,7 @@ #include "TPCCalibration/CalibRawBase.h" class TH2D; +class TH2Poly; namespace o2 { @@ -50,6 +51,8 @@ class SimpleEventDisplay : public CalibRawBase Int_t updateCRU(const CRU& cru, const Int_t row, const Int_t pad, const Int_t timeBin, const Float_t signal) final { return 0; } + void updateSectorHists(); + CalPad* getCalPadMax() { return &mPadMax; } CalPad* getCalPadOccupancy() { return &mPadOccupancy; } @@ -71,6 +74,11 @@ class SimpleEventDisplay : public CalibRawBase TH1D* makePadSignals(Int_t roc, Int_t row, Int_t pad); + TH2D* getSigIROC() const { return mHSigIROC; } + TH2D* getSigOROC() const { return mHSigOROC; } + + void fillSectorHistSingleTimeBin(TH2Poly* h, Int_t timeBin); + /// set time bin range void setTimeBinRange(int firstBin, int lastBin) { @@ -79,8 +87,11 @@ class SimpleEventDisplay : public CalibRawBase initHistograms(); } + Int_t getFirstTimeBin() const { return mFirstTimeBin; } + Int_t getLastTimeBin() const { return mLastTimeBin; } + /// Dummy end event - void endEvent() final{}; + void endEvent() final {}; private: CalPad mPadMax; ///< Cal Pad with max Entry per channel diff --git a/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplayGUI.h b/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplayGUI.h index 8000cea04a813..21dac37212115 100644 --- a/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplayGUI.h +++ b/Detectors/TPC/monitor/include/TPCMonitor/SimpleEventDisplayGUI.h @@ -17,10 +17,13 @@ #define TPC_SimpleEventDisplayGUI_H_ #include +#include #include "TString.h" #include "TPCMonitor/SimpleEventDisplay.h" +#include "DataFormatsTPC/ClusterNative.h" +#include "DataFormatsTPC/ClusterNativeHelper.h" class TH2F; class TH1F; @@ -28,6 +31,9 @@ class TH1; class TGTextEntry; class TGTextButton; class TGCheckButton; +class TGNumberEntry; +class TGVButtonGroup; +class TH2Poly; namespace o2::tpc { @@ -47,6 +53,9 @@ class SimpleEventDisplayGUI void toggleFFT(); void toggleOccupancy(); + void togglePadTime(); + void toggleSingleTimeBin(); + void toggleClusters(); void monitorGui(); void exitRoot(); void update(TString clist); @@ -60,6 +69,8 @@ class SimpleEventDisplayGUI void next(int eventNumber = -1); void callEventNumber(); void applySignalThreshold(); + void selectTimeBin(); + void showClusters(int roc, int row); void runSimpleEventDisplay(std::string_view fileInfo, std::string_view pedestalFile = "", int firstTimeBin = 0, int lastTimeBin = 500, int nTimeBinsPerCall = 500, uint32_t verbosity = 0, uint32_t debugLevel = 0, int selectedSector = 0, bool showSides = 1); @@ -103,17 +114,45 @@ class SimpleEventDisplayGUI TH2F* mHOccupancyC = nullptr; TH2F* mHOccupancyIROC = nullptr; TH2F* mHOccupancyOROC = nullptr; - + TH2F* mHPadTimeIROC = nullptr; + TH2F* mHPadTimeOROC = nullptr; + TH2Poly* mSectorPolyTimeBin = nullptr; + TPolyMarker* mClustersIROC = nullptr; + TPolyMarker* mClustersOROC = nullptr; + TPolyMarker* mClustersRowPad = nullptr; + + TGCheckButton* mCheckSingleTB = nullptr; TGCheckButton* mCheckFFT = nullptr; TGCheckButton* mCheckOccupancy = nullptr; + TGCheckButton* mCheckPadTime = nullptr; + TGCheckButton* mCheckShowClusters = nullptr; + static constexpr int NCheckClFlags = 5; + TGCheckButton* mCheckClFlags[NCheckClFlags] = {}; + TGVButtonGroup* mFlagGroup = nullptr; TGTextEntry* mEventNumber = nullptr; TGTextEntry* mSignalThresholdValue = nullptr; + TGNumberEntry* mSelTimeBin = nullptr; + + std::string mInputFileInfo{}; + + o2::tpc::ClusterNativeHelper::Reader mTPCclusterReader; + o2::tpc::ClusterNativeAccess mClusterIndex; + std::unique_ptr mClusterBuffer; + o2::tpc::ClusterNativeHelper::ConstMCLabelContainerViewWithBuffer mClusterMCBuffer; TH1* getBinInfoXY(int& binx, int& biny, float& bincx, float& bincy); void initOccupancyHists(); void deleteOccupancyHists(); + void initPadTimeHists(); + void deletePadTimeHists(); + + void initSingleTBHists(); + void deleteSingleTBHists(); + + void fillClusters(Long64_t entry); + ClassDefNV(SimpleEventDisplayGUI, 0); }; diff --git a/Detectors/TPC/monitor/src/SimpleEventDisplay.cxx b/Detectors/TPC/monitor/src/SimpleEventDisplay.cxx index 5c68ca497c453..5953b93355f6e 100644 --- a/Detectors/TPC/monitor/src/SimpleEventDisplay.cxx +++ b/Detectors/TPC/monitor/src/SimpleEventDisplay.cxx @@ -16,6 +16,7 @@ #include "TH2S.h" #include "TROOT.h" #include "TString.h" +#include "TH2Poly.h" #include "DataFormatsTPC/Defs.h" #include "TPCBase/CalArray.h" @@ -158,6 +159,17 @@ Int_t SimpleEventDisplay::updateROC(const Int_t roc, return 0; } +//_____________________________________________________________________ +void SimpleEventDisplay::updateSectorHists() +{ + if (mSelectedSector % 36 != mLastSelSector % 36) { + mSectorLoop = kTRUE; + processEvent(getPresentEventNumber()); + mLastSelSector = mSelectedSector; + mSectorLoop = kFALSE; + } +} + //_____________________________________________________________________ TH1D* SimpleEventDisplay::makePadSignals(Int_t roc, Int_t row, Int_t pad) { @@ -177,17 +189,47 @@ TH1D* SimpleEventDisplay::makePadSignals(Int_t roc, Int_t row, Int_t pad) mSelectedSector = roc; // attention change for if event has changed - if (mSelectedSector % 36 != mLastSelSector % 36) { - mSectorLoop = kTRUE; - processEvent(getPresentEventNumber()); - mLastSelSector = mSelectedSector; - mSectorLoop = kFALSE; - } - TH1D* h = nullptr; + updateSectorHists(); + const Int_t nbins = mLastTimeBin - mFirstTimeBin; if (nbins <= 0) { return nullptr; } + + TH2D* hPadSignals = nullptr; + + // ===| ADC vs. Pad vs. Time for row |======================================== + TH2F* hPadTime = nullptr; + if (roc < (Int_t)mTPCmapper.getNumberOfIROCs()) { + hPadTime = static_cast(gROOT->FindObject("hPadTimeValsI")); + hPadSignals = mHSigIROC; + } else { + hPadTime = static_cast(gROOT->FindObject("hPadTimeValsO")); + hPadSignals = mHSigOROC; + } + + static Int_t lastRoc = -1; + static Int_t lastRow = -1; + if (hPadTime && ((lastRoc != roc) || (lastRow != row))) { + hPadTime->Reset(); + const auto nPads = mTPCmapper.getNumberOfPadsInRowROC(roc, row); + const auto nBins = hPadTime->GetNbinsY(); + const auto shift = nBins / 2 - nPads / 2; + for (int iPad = 0; iPad < nPads; ++iPad) { + const int ichannel = mTPCmapper.getPadNumberInROC(PadROCPos(roc, row, iPad)); + const Int_t offset = (nbins + 2) * (ichannel + 1); + const double* arrSig = hPadSignals->GetArray() + offset; + for (int iTime = 0; iTime < nbins; ++iTime) { + hPadTime->SetBinContent(iTime + 1, iPad + shift + 1, arrSig[iTime + 1]); + } + } + hPadTime->SetEntries(nPads * nbins); + hPadTime->SetTitle(fmt::format("Pad row {}", row).data()); + hPadTime->SetUniqueID(row); + } + + // ===| ADC vs. time for single pad |========================================= + TH1D* h = nullptr; const Int_t offset = (nbins + 2) * (channel + 1); Double_t* arrP = nullptr; @@ -196,15 +238,15 @@ TH1D* SimpleEventDisplay::makePadSignals(Int_t roc, Int_t row, Int_t pad) if (roc < (Int_t)mTPCmapper.getNumberOfIROCs()) { h = (TH1D*)gROOT->FindObject("PadSignals_IROC"); if (!h) { - h = new TH1D("PadSignals_IROC", "PadSignals IROC;time bins (200ns);amplitude (ADC counts)", nbins, mFirstTimeBin, mLastTimeBin); + h = new TH1D("PadSignals_IROC", "PadSignals IROC;time bin (200ns);amplitude (ADC counts)", nbins, mFirstTimeBin, mLastTimeBin); } h->SetFillColor(kBlue - 10); arrP = mHSigIROC->GetArray() + offset; - // title+="IROC "; + title += "IROC "; } else { h = (TH1D*)gROOT->FindObject("PadSignals_OROC"); if (!h) { - h = new TH1D("PadSignals_OROC", "PadSignals OROC;time bins (200ns);amplitude (ADC counts)", nbins, mFirstTimeBin, mLastTimeBin); + h = new TH1D("PadSignals_OROC", "PadSignals OROC;time bin (200ns);amplitude (ADC counts)", nbins, mFirstTimeBin, mLastTimeBin); } h->SetFillColor(kBlue - 10); arrP = mHSigOROC->GetArray() + offset; @@ -223,6 +265,7 @@ TH1D* SimpleEventDisplay::makePadSignals(Int_t roc, Int_t row, Int_t pad) h->SetEntries(entries); return h; } + //_____________________________________________________________________ void SimpleEventDisplay::resetEvent() { @@ -236,3 +279,28 @@ void SimpleEventDisplay::resetEvent() mHSigIROC->Reset(); mHSigOROC->Reset(); } + +//______________________________________________________________________________ +void SimpleEventDisplay::fillSectorHistSingleTimeBin(TH2Poly* h, Int_t timeBin) +{ + if (!h) { + return; + } + if (timeBin < mFirstTimeBin || timeBin > mLastTimeBin) { + return; + } + + int ichannel = 0; + const int iTimeBin = timeBin - mFirstTimeBin + 1; + // IROC loop + for (int ipad = 0; ipad < mHSigIROC->GetNbinsY(); ++ipad, ++ichannel) { + h->SetBinContent(ichannel + 1, mHSigIROC->GetBinContent(iTimeBin, ipad + 1)); + } + + // OROC loop + for (int ipad = 0; ipad < mHSigOROC->GetNbinsY(); ++ipad, ++ichannel) { + h->SetBinContent(ichannel + 1, mHSigOROC->GetBinContent(iTimeBin, ipad + 1)); + } + + h->SetEntries(ichannel); +} diff --git a/Detectors/TPC/monitor/src/SimpleEventDisplayGUI.cxx b/Detectors/TPC/monitor/src/SimpleEventDisplayGUI.cxx index ac3f08ec37743..20da28eefe364 100644 --- a/Detectors/TPC/monitor/src/SimpleEventDisplayGUI.cxx +++ b/Detectors/TPC/monitor/src/SimpleEventDisplayGUI.cxx @@ -15,17 +15,24 @@ #include #include #include +#include #include "TGFrame.h" #include "TGTextEntry.h" #include "TGLabel.h" #include "TGButton.h" +#include "TGNumberEntry.h" +#include "TGButtonGroup.h" #include "TQObject.h" +#include "TH2Poly.h" +#include "TPolyMarker.h" +#include "TLine.h" #include "TH1F.h" #include "TH2F.h" #include "TFile.h" #include "TSystem.h" +#include "TStyle.h" #include "TCanvas.h" #include "TObjArray.h" #include "TROOT.h" @@ -34,31 +41,40 @@ #include +#include "GPUTPCGeometry.h" #include "TPCBase/Mapper.h" #include "TPCBase/CalDet.h" #include "TPCBase/CalArray.h" #include "TPCBase/Painter.h" +#include "DataFormatsTPC/Constants.h" #include "TPCMonitor/SimpleEventDisplayGUI.h" using namespace o2::tpc; +namespace fs = std::filesystem; //__________________________________________________________________________ void SimpleEventDisplayGUI::monitorGui() { - float xsize = 145; + float xsize = 160; float ysize = 25; float yoffset = 10; float ysize_dist = 2; - float mainx = 170; - float mainy = 200; + float mainx = xsize + 2 * 10; + float mainy = 335; int ycount = 0; + float currentY = yoffset + ycount * (ysize_dist + ysize); - TGMainFrame* mFrameMain = new TGMainFrame(gClient->GetRoot(), 200, 200, kMainFrame | kVerticalFrame); + auto nextY = [&ycount, ¤tY, yoffset, ysize, ysize_dist]() { + ++ycount; + currentY = yoffset + ycount * (ysize_dist + ysize); + }; + + TGMainFrame* mFrameMain = new TGMainFrame(gClient->GetRoot(), mainx, mainy, kMainFrame | kVerticalFrame); mFrameMain->SetLayoutBroken(kTRUE); mFrameMain->SetCleanup(kDeepCleanup); - TGCompositeFrame* mContRight = new TGCompositeFrame(mFrameMain, 155, mainy, kVerticalFrame | kFixedWidth | kFitHeight); + TGCompositeFrame* mContRight = new TGCompositeFrame(mFrameMain, xsize + 5, mainy, kVerticalFrame | kFixedWidth | kFitHeight); mFrameMain->AddFrame(mContRight, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandY | kLHintsExpandX, 3, 5, 3, 3)); //--------------------------- @@ -68,8 +84,8 @@ void SimpleEventDisplayGUI::monitorGui() mFrameNextEvent->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "next(=-1)"); mFrameNextEvent->SetTextColor(200); mFrameNextEvent->SetToolTipText("Go to next event"); - mFrameNextEvent->MoveResize(10, yoffset + ycount * (ysize_dist + ysize), xsize, (unsigned int)ysize); - ++ycount; + mFrameNextEvent->MoveResize(10, currentY, xsize, (unsigned int)ysize); + nextY(); //--------------------------- TGTextButton* mFramePreviousEvent = new TGTextButton(mContRight, "&Previous Event"); @@ -81,8 +97,8 @@ void SimpleEventDisplayGUI::monitorGui() mFramePreviousEvent->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "next(=-2)"); mFramePreviousEvent->SetTextColor(200); mFramePreviousEvent->SetToolTipText("Go to previous event"); - mFramePreviousEvent->MoveResize(10, yoffset + ycount * (ysize_dist + ysize), xsize, (unsigned int)ysize); - ++ycount; + mFramePreviousEvent->MoveResize(10, currentY, xsize, (unsigned int)ysize); + nextY(); //--------------------------- @@ -91,7 +107,7 @@ void SimpleEventDisplayGUI::monitorGui() mGoToEvent->SetTextColor(200); mGoToEvent->SetToolTipText("Go to event"); - mGoToEvent->MoveResize(10, yoffset + ycount * (ysize_dist + ysize), 0.65 * xsize, (unsigned int)ysize); + mGoToEvent->MoveResize(10, currentY, 0.65 * xsize, (unsigned int)ysize); mGoToEvent->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "callEventNumber()"); // @@ -99,9 +115,9 @@ void SimpleEventDisplayGUI::monitorGui() ftbuf->AddText(0, "0"); mEventNumber = new TGTextEntry(mContRight, ftbuf); mContRight->AddFrame(mEventNumber, new TGLayoutHints(kFitHeight)); - mEventNumber->MoveResize(0.7 * xsize, yoffset + ycount * (ysize_dist + ysize), 0.3 * xsize, (unsigned int)ysize); + mEventNumber->MoveResize(0.7 * xsize, currentY, 0.3 * xsize, (unsigned int)ysize); mEventNumber->SetAlignment(kTextRight); - ++ycount; + nextY(); //--------------------------- TGTextButton* mApplySignalThreshold = new TGTextButton(mContRight, "&Apply Threshold"); @@ -109,16 +125,36 @@ void SimpleEventDisplayGUI::monitorGui() mApplySignalThreshold->SetTextColor(200); mApplySignalThreshold->SetToolTipText("Apply Threshold"); - mApplySignalThreshold->MoveResize(10, yoffset + ycount * (ysize_dist + ysize), 0.65 * xsize, (unsigned int)ysize); + mApplySignalThreshold->MoveResize(10, currentY, 0.65 * xsize, (unsigned int)ysize); mApplySignalThreshold->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "applySignalThreshold()"); auto* signalThresholdBuf = new TGTextBuffer(10); signalThresholdBuf->AddText(0, "0"); mSignalThresholdValue = new TGTextEntry(mContRight, signalThresholdBuf); - mSignalThresholdValue->MoveResize(0.7 * xsize, yoffset + ycount * (ysize_dist + ysize), 0.3 * xsize, (unsigned int)ysize); + mSignalThresholdValue->MoveResize(0.7 * xsize, currentY, 0.3 * xsize, (unsigned int)ysize); mSignalThresholdValue->SetAlignment(kTextRight); mSignalThresholdValue->Connect("ReturnPressed()", "o2::tpc::SimpleEventDisplayGUI", this, "applySignalThreshold()"); - ++ycount; + nextY(); + + //--------------------------- + mCheckSingleTB = new TGCheckButton(mContRight, "One TB"); + mContRight->AddFrame(mCheckSingleTB, new TGLayoutHints(kLHintsExpandX)); + + mCheckSingleTB->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "toggleSingleTimeBin()"); + mCheckSingleTB->SetTextColor(200); + mCheckSingleTB->SetToolTipText("Show single time bin"); + mCheckSingleTB->MoveResize(10, currentY, 0.5 * xsize, (unsigned int)ysize); + mCheckSingleTB->SetDown(0); + + mSelTimeBin = new TGNumberEntry(mContRight, mEvDisp.getFirstTimeBin(), 6, 999, TGNumberFormat::kNESInteger, + TGNumberFormat::kNEAPositive, + TGNumberFormat::kNELLimitMinMax, + mEvDisp.getFirstTimeBin(), mEvDisp.getLastTimeBin()); + + mSelTimeBin->MoveResize(0.55 * xsize, currentY, 0.45 * xsize, (unsigned int)ysize); + mSelTimeBin->Connect("ValueSet(Long_t)", "o2::tpc::SimpleEventDisplayGUI", this, "selectTimeBin()"); + (mSelTimeBin->GetNumberEntry())->Connect("ReturnPressed()", "o2::tpc::SimpleEventDisplayGUI", this, "selectTimeBin()"); + nextY(); //--------------------------- mCheckFFT = new TGCheckButton(mContRight, "Show FFT"); @@ -127,9 +163,10 @@ void SimpleEventDisplayGUI::monitorGui() mCheckFFT->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "toggleFFT()"); mCheckFFT->SetTextColor(200); mCheckFFT->SetToolTipText("Switch on FFT calculation"); - mCheckFFT->MoveResize(10, 10 + ysize * 4, xsize, (unsigned int)ysize); + mCheckFFT->MoveResize(10, currentY, xsize, (unsigned int)ysize); mCheckFFT->SetDown(0); toggleFFT(); + nextY(); //--------------------------- mCheckOccupancy = new TGCheckButton(mContRight, "Show Occupancy"); @@ -138,9 +175,54 @@ void SimpleEventDisplayGUI::monitorGui() mCheckOccupancy->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "toggleOccupancy()"); mCheckOccupancy->SetTextColor(200); mCheckOccupancy->SetToolTipText("Switch on Occupancy calculation"); - mCheckOccupancy->MoveResize(10, 10 + ysize * 5, xsize, (unsigned int)ysize); + mCheckOccupancy->MoveResize(10, currentY, xsize, (unsigned int)ysize); mCheckOccupancy->SetDown(0); toggleOccupancy(); + nextY(); + + //--------------------------- + mCheckPadTime = new TGCheckButton(mContRight, "Show PadTime"); + mContRight->AddFrame(mCheckPadTime, new TGLayoutHints(kLHintsExpandX)); + + mCheckPadTime->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "togglePadTime()"); + mCheckPadTime->SetTextColor(200); + mCheckPadTime->SetToolTipText("Switch on PadTime calculation"); + mCheckPadTime->MoveResize(10, currentY, xsize, (unsigned int)ysize); + mCheckPadTime->SetDown(0); + nextY(); + + //--------------------------- + mCheckShowClusters = new TGCheckButton(mContRight, "Overlay clusters"); + mContRight->AddFrame(mCheckShowClusters, new TGLayoutHints(kLHintsExpandX)); + + mCheckShowClusters->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "toggleClusters()"); + mCheckShowClusters->SetTextColor(200); + mCheckShowClusters->SetToolTipText("Switch on ShowClusters calculation"); + mCheckShowClusters->MoveResize(10, currentY, xsize, (unsigned int)ysize); + mCheckShowClusters->SetDown(0); + mCheckShowClusters->SetEnabled(kFALSE); + + nextY(); + + //--------------------------- + mFlagGroup = new TGVButtonGroup(mContRight, "Cl Flags"); + auto hframe = new TGHorizontalFrame(mFlagGroup); + const std::string flagTips[NCheckClFlags] = {"Golden", "Split Pad", "Split Time", "Edge", "Single Pad and/or Time"}; + for (int iCheck = 0; iCheck < NCheckClFlags; ++iCheck) { + mCheckClFlags[iCheck] = new TGCheckButton(hframe, "", 10000 + iCheck); + mCheckClFlags[iCheck]->SetToolTipText(flagTips[iCheck].data()); + mCheckClFlags[iCheck]->SetDown(1); + mCheckClFlags[iCheck]->SetEnabled(kFALSE); + mCheckClFlags[iCheck]->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "showClusters(=-1,-1)"); + hframe->AddFrame(mCheckClFlags[iCheck], new TGLayoutHints(kLHintsExpandX)); + } + mFlagGroup->AddFrame(hframe, new TGLayoutHints(kLHintsExpandX)); + mFlagGroup->Show(); + mFlagGroup->MoveResize(10, currentY, xsize, (unsigned int)2 * ysize); + mContRight->AddFrame(mFlagGroup, new TGLayoutHints(kLHintsExpandX)); + mFlagGroup->SetState(kFALSE); + nextY(); + nextY(); //--------------------------- TGTextButton* mFrameExit = new TGTextButton(mContRight, "Exit ROOT"); @@ -149,13 +231,14 @@ void SimpleEventDisplayGUI::monitorGui() mFrameExit->Connect("Clicked()", "o2::tpc::SimpleEventDisplayGUI", this, "exitRoot()"); mFrameExit->SetTextColor(200); mFrameExit->SetToolTipText("Exit the ROOT process"); - mFrameExit->MoveResize(10, 10 + ysize * 6, xsize, (unsigned int)ysize); + mFrameExit->MoveResize(10, currentY, xsize, (unsigned int)ysize); + nextY(); //--------------------------- mFrameMain->MapSubwindows(); mFrameMain->MapWindow(); mFrameMain->SetWindowName("OM"); - mFrameMain->MoveResize(50, 50, (unsigned int)mainx, (unsigned int)mainy); + mFrameMain->MoveResize(50, 50, (unsigned int)mainx, (unsigned int)currentY + 20); mFrameMain->Move(4 * 400 + 10, 10); } @@ -182,6 +265,7 @@ void SimpleEventDisplayGUI::toggleFFT() } } +//______________________________________________________________________________ void SimpleEventDisplayGUI::initOccupancyHists() { const int w = 400; @@ -266,6 +350,120 @@ void SimpleEventDisplayGUI::deleteOccupancyHists() delete gROOT->GetListOfCanvases()->FindObject("hOccupancyValsOROC"); } +void SimpleEventDisplayGUI::initPadTimeHists() +{ + // histograms and canvases for pad vs. time values IROC + const int w = 400; + const int h = 400; + const int hOff = 60; + const int vOff = 4; + TCanvas* c = nullptr; + + const Int_t firstTimeBin = mEvDisp.getFirstTimeBin(); + const Int_t lastTimeBin = mEvDisp.getLastTimeBin(); + const Int_t nTimeBins = mEvDisp.getLastTimeBin() - mEvDisp.getFirstTimeBin(); + + c = new TCanvas("PadTimeValsI", "PadTimeValsI", -3 * (w + vOff), 0 * h, w, h); + + c->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", + "o2::tpc::SimpleEventDisplayGUI", this, + "drawPadSignal(int,int,int,TObject*)"); + mHPadTimeIROC = new TH2F("hPadTimeValsI", "PadTime Values IROC;time bin;pad", nTimeBins, firstTimeBin, lastTimeBin, 108, -54, 54); + // mHPadTimeIROC->SetDirectory(nullptr); + mHPadTimeIROC->SetStats(kFALSE); + mHPadTimeIROC->Draw("colz"); + if (!mClustersIROC) { + mClustersIROC = new TPolyMarker; + mClustersIROC->SetMarkerSize(1); + mClustersIROC->SetMarkerStyle(29); + mClustersIROC->SetMarkerColor(kMagenta); + mClustersIROC->Draw(); + } + + // histograms and canvases for pad vs. time values OROC + c = new TCanvas("PadTimeValsO", "PadTimeValsO", -3 * (w + vOff), 1 * h + hOff, w, h); + + c->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", + "o2::tpc::SimpleEventDisplayGUI", this, + "drawPadSignal(int,int,int,TObject*)"); + mHPadTimeOROC = new TH2F("hPadTimeValsO", "PadTime Values OROC;time bin;pad", nTimeBins, firstTimeBin, lastTimeBin, 140, -70, 70); + // mHPadTimeOROC->SetDirectory(nullptr); + mHPadTimeOROC->SetStats(kFALSE); + mHPadTimeOROC->Draw("colz"); + if (!mClustersOROC) { + mClustersOROC = new TPolyMarker; + mClustersOROC->SetMarkerSize(1); + mClustersOROC->SetMarkerStyle(29); + mClustersOROC->SetMarkerColor(kMagenta); + mClustersOROC->Draw(); + } +} + +void SimpleEventDisplayGUI::deletePadTimeHists() +{ + delete gROOT->GetListOfCanvases()->FindObject("PadTimeValsO"); + delete mHPadTimeOROC; + mHPadTimeOROC = nullptr; + + delete gROOT->GetListOfCanvases()->FindObject("PadTimeValsI"); + delete mHPadTimeIROC; + mHPadTimeIROC = nullptr; + + delete gROOT->GetListOfCanvases()->FindObject("hPadTimeValsIROC"); + delete gROOT->GetListOfCanvases()->FindObject("hPadTimeValsOROC"); +} + +void SimpleEventDisplayGUI::initSingleTBHists() +{ + // histograms and canvases for pad vs. time values IROC + const int w = 400; + const int h = 400; + const int hOff = 60; + const int vOff = 4; + TCanvas* c = nullptr; + + const Int_t firstTimeBin = mEvDisp.getFirstTimeBin(); + const Int_t lastTimeBin = mEvDisp.getLastTimeBin(); + const Int_t nTimeBins = mEvDisp.getLastTimeBin() - mEvDisp.getFirstTimeBin(); + + c = new TCanvas("SingleTB", "SingleTB", -3 * (w + vOff), 1 * h + hOff, 1.8 * w, h); + + c->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", + "o2::tpc::SimpleEventDisplayGUI", this, + "drawPadSignal(int,int,int,TObject*)"); + mSectorPolyTimeBin = painter::makeSectorHist("hSingleTB"); + // mHPadTimeIROC->SetDirectory(nullptr); + mSectorPolyTimeBin->SetStats(kFALSE); + mSectorPolyTimeBin->Draw("colz"); + + if (!mClustersRowPad) { + mClustersRowPad = new TPolyMarker; + mClustersRowPad->SetMarkerSize(1); + mClustersRowPad->SetMarkerStyle(29); + mClustersRowPad->SetMarkerColor(kMagenta); + } + mClustersRowPad->Draw(); +} + +void SimpleEventDisplayGUI::deleteSingleTBHists() +{ + delete gROOT->GetListOfCanvases()->FindObject("SingleTB"); + delete mSectorPolyTimeBin; + mSectorPolyTimeBin = nullptr; +} + +//__________________________________________________________________________ +void SimpleEventDisplayGUI::togglePadTime() +{ + if (mCheckPadTime->IsDown()) { + initPadTimeHists(); + mCheckShowClusters->SetEnabled(kTRUE); + } else { + deletePadTimeHists(); + mCheckShowClusters->SetEnabled(kFALSE); + } +} + //__________________________________________________________________________ void SimpleEventDisplayGUI::toggleOccupancy() { @@ -276,6 +474,58 @@ void SimpleEventDisplayGUI::toggleOccupancy() } } +//__________________________________________________________________________ +void SimpleEventDisplayGUI::toggleSingleTimeBin() +{ + if (mCheckSingleTB->IsDown()) { + initSingleTBHists(); + selectTimeBin(); + } else { + deleteSingleTBHists(); + if (mClustersRowPad) { + mClustersRowPad->SetPolyMarker(0); + } + } +} + +//______________________________________________________________________________ +void SimpleEventDisplayGUI::toggleClusters() +{ + if (mCheckShowClusters->IsDown()) { + if (mTPCclusterReader.getTreeSize() > 0) { + return; + } + fs::path p{mInputFileInfo}; + std::string clusterFile = fmt::format("{}/tpc-native-clusters.root", p.parent_path().c_str()); + if (!fs::exists(clusterFile)) { + LOGP(warn, "Clusters file '{}' does not exist, trying local 'tpc-native-clusters.root'", clusterFile); + clusterFile = "tpc-native-clusters.root"; + if (!fs::exists(clusterFile)) { + LOGP(error, "Clusters file '{}' does not exist, can't load clusters", clusterFile); + return; + } + } + LOGP(info, "loading clusters from file '{}'", clusterFile); + mTPCclusterReader.init(clusterFile.data()); + gROOT->cd(); + const auto presentEventNumber = mEvDisp.getPresentEventNumber(); + fillClusters(presentEventNumber); + mFlagGroup->SetState(kTRUE); + for (int iCheck = 0; iCheck < NCheckClFlags; ++iCheck) { + mCheckClFlags[iCheck]->SetEnabled(kTRUE); + } + } else { + if (mClustersIROC) { + mClustersIROC->SetPolyMarker(0); + mClustersOROC->SetPolyMarker(0); + } + mFlagGroup->SetState(kFALSE); + for (int iCheck = 0; iCheck < NCheckClFlags; ++iCheck) { + mCheckClFlags[iCheck]->SetEnabled(kFALSE); + } + } +} + //__________________________________________________________________________ void SimpleEventDisplayGUI::exitRoot() { @@ -368,10 +618,19 @@ TH1* SimpleEventDisplayGUI::getBinInfoXY(int& binx, int& biny, float& bincx, flo const float yy = pad->AbsPixeltoY(py); const float y = pad->PadtoX(yy); - binx = h->GetXaxis()->FindBin(x); - biny = h->GetYaxis()->FindBin(y); - bincx = h->GetXaxis()->GetBinCenter(binx); - bincy = h->GetYaxis()->GetBinCenter(biny); + if (h->InheritsFrom(TH2Poly::Class())) { + auto hPoly = (TH2Poly*)h; + binx = hPoly->GetXaxis()->FindBin(x); + biny = hPoly->GetYaxis()->FindBin(y); + bincx = hPoly->GetXaxis()->GetBinCenter(binx); + bincy = hPoly->GetYaxis()->GetBinCenter(biny); + binx = biny = hPoly->FindBin(x, y); + } else { + binx = h->GetXaxis()->FindBin(x); + biny = h->GetYaxis()->FindBin(y); + bincx = h->GetXaxis()->GetBinCenter(binx); + bincy = h->GetYaxis()->GetBinCenter(biny); + } return h; } @@ -383,18 +642,11 @@ void SimpleEventDisplayGUI::drawPadSignal(int event, int x, int y, TObject* o) // type: name of canvas // + // fmt::print("o: {}, type: {}, name: {}\n", (void*)o, o ? o->IsA()->GetName() : "", o ? o->GetName() : ""); if (!o) { return; } - TString type; - if (std::string_view(o->GetName()) == "hMaxValsIROC" || std::string_view(o->GetName()) == "hOccupancyValsIROC") { - type = "SigI"; - } else if (std::string_view(o->GetName()) == "hMaxValsOROC" || std::string_view(o->GetName()) == "hOccupancyValsOROC") { - type = "SigO"; - } else { - return; - } // check if an event was alreay loaded if (!mEvDisp.getNumberOfProcessedEvents()) { return; @@ -411,25 +663,62 @@ void SimpleEventDisplayGUI::drawPadSignal(int event, int x, int y, TObject* o) if (!h) { return; } + // fmt::print("binx {}, biny {}, cx {}, cy {}\n", binx, biny, bincx, bincy); + + const auto& mapper = Mapper::instance(); + // int roc = h->GetUniqueID(); + int roc = mSelectedSector; + TString type; + const std::string_view objectName(o->GetName()); + + // for standard row vs cpad histo, is overwritte in case of TH2Poly sector histo below + int row = int(TMath::Floor(bincx)); - const int row = int(TMath::Floor(bincx)); - const int cpad = int(TMath::Floor(bincy)); // find pad and channel - const int roc = h->GetUniqueID(); - if (roc < 0 || roc >= (int)ROC::MaxROC) { + int pad = -1; + + if (objectName == "hMaxValsIROC" || objectName == "hOccupancyValsIROC") { + type = "SigI"; + } else if (objectName == "hMaxValsOROC" || objectName == "hOccupancyValsOROC") { + type = "SigO"; + roc += 36; + } else if (objectName == "hPadTimeValsI") { + type = "SigI"; + row = h->GetUniqueID(); + } else if (objectName == "hPadTimeValsO") { + type = "SigO"; + row = h->GetUniqueID(); + roc += 36; + } else if (objectName == "hSingleTB") { + type = "SigI"; + const auto padPosSec = mapper.padPos(binx - 1); + pad = padPosSec.getPad(); + row = padPosSec.getRow(); + if (bincx > 133) { + type = "SigO"; + roc += 36; + row -= mapper.getNumberOfRowsROC(0); + } + // fmt::print("roc {}, row {}, pad {}\n", roc, row, pad); + } else { return; } + const int nPads = mapper.getNumberOfPadsInRowROC(roc, row); + if (pad == -1) { + const int cpad = int(TMath::Floor(bincy)); + pad = cpad + nPads / 2; + } - const auto& mapper = Mapper::instance(); + if (pad < 0 || pad >= (int)nPads) { + return; + } if (row < 0 || row >= (int)mapper.getNumberOfRowsROC(roc)) { return; } - - const int nPads = mapper.getNumberOfPadsInRowROC(roc, row); - const int pad = cpad + nPads / 2; - if (pad < 0 || pad >= (int)nPads) { + if (roc < 0 || roc >= (int)ROC::MaxROC) { return; } + const TString rocType = (roc < 36) ? "I" : "O"; // draw requested pad signal @@ -456,7 +745,7 @@ void SimpleEventDisplayGUI::drawPadSignal(int event, int x, int y, TObject* o) xax->SetRange(2, nbinsx / 2); if (init) { xax->Set(nbinsx, xax->GetXmin() / maxTime, xax->GetXmax() / maxTime); - hFFT->SetNameTitle(Form("hFFT_%sROC", (roc < 36) ? "I" : "O"), "FFT magnitude;frequency (kHz);amplitude"); + hFFT->SetNameTitle(Form("hFFT_%sROC", rocType.Data()), "FFT magnitude;frequency (kHz);amplitude"); } hFFT->Scale(2. / (nbinsx - 1)); cFFT->cd(); @@ -464,7 +753,28 @@ void SimpleEventDisplayGUI::drawPadSignal(int event, int x, int y, TObject* o) } } } - update(Form("%s;%sFFT", type.Data(), type.Data())); + if (mCheckSingleTB) { + TLine l; + l.SetLineColor(kRed); + const auto timeBin = mSelTimeBin->GetNumberEntry()->GetIntNumber(); + h = (TH1D*)gROOT->FindObject(fmt::format("PadSignals_{}ROC", rocType.Data()).data()); + if (h) { + l.DrawLine(timeBin + 0.5, h->GetMinimum(), timeBin + 0.5, h->GetMaximum()); + } + } + if (mCheckPadTime && objectName.find("hPadTimeVals") == 0) { + TLine l; + l.SetLineColor(kMagenta); + const auto timeBin = bincx; + h = (TH1D*)gROOT->FindObject(fmt::format("PadSignals_{}ROC", rocType.Data()).data()); + if (h) { + l.DrawLine(timeBin + 0.5, h->GetMinimum(), timeBin, h->GetMaximum()); + } + } + if (mCheckShowClusters->IsDown()) { + showClusters(roc, row); + } + update(Form("%s;%sFFT;PadTimeVals%s;SingleTB", type.Data(), type.Data(), rocType.Data())); } // printf("bin=%03d.%03d(%03d)[%05d], name=%s, ROC=%02d content=%.1f, ev: %d\n",row,pad,cpad,chn,h->GetName(), roc, h->GetBinContent(binx,biny), event); } @@ -546,6 +856,8 @@ void SimpleEventDisplayGUI::selectSector(int sector) if (mCheckOccupancy->IsDown()) { fillHists(1, Occupancy); } + mEvDisp.updateSectorHists(); + selectTimeBin(); } //__________________________________________________________________________ @@ -751,6 +1063,8 @@ void SimpleEventDisplayGUI::next(int eventNumber) if (mRunMode == RunMode::Online) { mProcessingEvent = false; } + + fillClusters(presentEventNumber); } //__________________________________________________________________________ @@ -765,6 +1079,7 @@ void SimpleEventDisplayGUI::runSimpleEventDisplay(std::string_view fileInfo, std { fair::Logger::SetVerbosity("LOW"); fair::Logger::SetConsoleSeverity("DEBUG"); + gStyle->SetNumberContours(255); if (pedestalFile.size()) { TFile f(pedestalFile.data()); if (f.IsOpen()) { @@ -788,6 +1103,10 @@ void SimpleEventDisplayGUI::runSimpleEventDisplay(std::string_view fileInfo, std monitorGui(); next(0); + + mInputFileInfo = fileInfo; + + memset(&mClusterIndex, 0, sizeof(mClusterIndex)); } //_____________________________________________________________________________ @@ -816,3 +1135,104 @@ void SimpleEventDisplayGUI::applySignalThreshold() mEvDisp.setSignalThreshold(signalThreshold); callEventNumber(); } + +//______________________________________________________________________________ +void SimpleEventDisplayGUI::selectTimeBin() +{ + if (!mCheckSingleTB->IsDown()) { + return; + } + const auto timeBin = mSelTimeBin->GetNumberEntry()->GetIntNumber(); + mEvDisp.fillSectorHistSingleTimeBin(mSectorPolyTimeBin, timeBin); + mSectorPolyTimeBin->SetTitle(fmt::format("Sector {:02}, time bin {:6}", mSelectedSector, timeBin).data()); + showClusters(-1, -1); + update("SingleTB"); +} + +//______________________________________________________________________________ +void SimpleEventDisplayGUI::showClusters(int roc, int row) +{ + static int lastRow = -1; + static int lastROC = -1; + static int lastTimeBin = -1; + const auto timeBin = mSelTimeBin->GetNumberEntry()->GetIntNumber(); + bool forceUpdate = false; + // fmt::print("roc {}, row {}, lastROC {}, lastRow {}\n", roc, row, lastROC, lastRow); + if (roc == -1) { + roc = lastROC; + forceUpdate = true; + } + if ((mTPCclusterReader.getTreeSize() == 0) || (lastRow == row) || (roc == -1)) { + return; + } + if (row == -1) { + if (lastRow == -1) { + return; + } + row = lastRow; + } + lastRow = row; + lastROC = roc; + + const auto& mapper = Mapper::instance(); + const int sector = roc % 36; + TPolyMarker* marker = mClustersIROC; + const int nPads = mapper.getNumberOfPadsInRowROC(roc, row); + + if (roc >= 36) { + marker = mClustersOROC; + row += mapper.getNumberOfRowsROC(0); // cluster access is using the global row in sector + } + + marker->SetPolyMarker(0); + if (mClustersRowPad) { + mClustersRowPad->SetPolyMarker(0); + } + size_t iSelClusters = 0; + int selFlags = 0; + bool golden = mCheckClFlags[0]->IsDown(); + for (int iFlag = 1; iFlag < NCheckClFlags; ++iFlag) { + selFlags += mCheckClFlags[iFlag]->IsDown() << (iFlag - 1); + } + const bool fillSingleTB = mCheckSingleTB->IsDown(); + const GPUCA_NAMESPACE::gpu::GPUTPCGeometry gpuGeom; + + const int rowMin = fillSingleTB ? 0 : row; + const int rowMax = fillSingleTB ? constants::MAXGLOBALPADROW : row + 1; + + for (int irow = rowMin; irow < rowMax; ++irow) { + const auto nClusters = mClusterIndex.nClusters[sector][irow]; + for (size_t icl = 0; icl < nClusters; ++icl) { + const auto& cl = mClusterIndex.clusters[sector][irow][icl]; + const auto flags = cl.getFlags(); + // fmt::print("flags: {}, selFlags: {}, selGolden: {}, ", flags, selFlags, golden); + if (((flags == 0) && golden) || (flags & selFlags)) { + // fmt::print("sel"); + if (row == irow) { + marker->SetPoint(iSelClusters, cl.getTime() + 0.5, cl.getPad() + 0.5 - nPads / 2.); + ++iSelClusters; + } + if (fillSingleTB && std::abs(cl.getTime() - timeBin) < 2) { + const auto ly = gpuGeom.LinearPad2Y(sector, irow, cl.getPad() + 0.5); + mClustersRowPad->SetNextPoint(gpuGeom.Row2X(irow), (sector >= GPUCA_NSLICES / 2) ? -ly : ly); + } + } + // fmt::print("\n"); + } + } + // marker->SetPolyMarker(iSelClusters); + + if (forceUpdate) { + update(Form("PadTimeVals%s;SingleTB", (roc < 36) ? "I" : "O")); + } +} + +//______________________________________________________________________________ +void SimpleEventDisplayGUI::fillClusters(Long64_t entry) +{ + if (mTPCclusterReader.getTreeSize() > 0) { + mTPCclusterReader.read(entry); + mTPCclusterReader.fillIndex(mClusterIndex, mClusterBuffer, mClusterMCBuffer); + LOGP(info, "Loaded cluster tree entry {} with {} clusters", entry, mClusterIndex.nClustersTotal); + } +}