From eaa7fbb3745567c59cf1266cfb7c8c5f5c44e85f Mon Sep 17 00:00:00 2001 From: wiechula <11199190+wiechula@users.noreply.github.com> Date: Mon, 23 Sep 2024 15:48:24 +0200 Subject: [PATCH] TPC: Multiple fixes and extensions (#13533) * fix completion policy * Add possibility for a common file name extension saving canvases * Extend FW parameter file creation * Allow for different thresholds for each ROC Type in pedestal file creation * Add common mode k-values in float precision and inverse k-factors with truncated precision * Digit class extension for simple drawing * Extend TPC refitter * possibility to dump ITS-TPC * Tsallis downsampling * MB sampling * shared flag added to native clusters * Charge info now via native clusters * Write full native clusters * add occupancy info * add cosmics refitting with TOF cluster time * Extend time gain calibration * Undo previous timeGain corrections to allow for residual calibration * slot length in seconds * slot extension for CCDB (for residual calibration) * simple looper cut * settable debug output name * dumping of calibration histograms per slot * debug output on track level * average entries for calibration * Update event display - Pad vs time view for a single row * visualisation of hovered time bin in ADC vs. time - cluster overlay in pad vs. time view * selection of cluster flags - Pad vs. row view for a single time bin * visualisation of hovered time bin in ADC vs. time --- .../DataFormatsTPC/CalibdEdxCorrection.h | 6 + .../TPC/include/DataFormatsTPC/TrackCuts.h | 13 +- .../Detectors/TPC/src/CalibdEdxCorrection.cxx | 20 + DataFormats/Detectors/TPC/src/TrackCuts.cxx | 3 + .../include/DetectorsBase/DPLWorkflowUtils.h | 1 + .../base/include/TPCBase/CRUCalibHelpers.h | 5 +- Detectors/TPC/base/include/TPCBase/Utils.h | 20 +- Detectors/TPC/base/src/CRUCalibHelpers.cxx | 24 +- Detectors/TPC/base/src/Utils.cxx | 12 +- Detectors/TPC/calibration/CMakeLists.txt | 4 +- .../include/TPCCalibration/CalibdEdx.h | 41 +- .../include/TPCCalibration/CalibratordEdx.h | 10 + .../include/TPCCalibration/DigitAdd.h | 39 + .../TPC/calibration/macro/prepareCMFiles.C | 21 + .../calibration/macro/preparePedestalFiles.C | 7 +- .../calibration/macro/preparePedestalFiles.sh | 10 +- Detectors/TPC/calibration/src/CalibdEdx.cxx | 88 ++- .../TPC/calibration/src/CalibratordEdx.cxx | 21 + Detectors/TPC/calibration/src/DigitAdd.cxx | 54 ++ .../calibration/src/TPCCalibrationLinkDef.h | 2 + .../include/TPCMonitor/SimpleEventDisplay.h | 13 +- .../TPCMonitor/SimpleEventDisplayGUI.h | 41 +- .../TPC/monitor/src/SimpleEventDisplay.cxx | 88 ++- .../TPC/monitor/src/SimpleEventDisplayGUI.cxx | 504 +++++++++++-- .../include/TPCWorkflow/TPCRefitter.h | 6 +- Detectors/TPC/workflow/src/CalibdEdxSpec.cxx | 24 +- .../TPC/workflow/src/CalibratordEdxSpec.cxx | 74 +- .../TPC/workflow/src/MIPTrackFilterSpec.cxx | 7 +- Detectors/TPC/workflow/src/TPCRefitter.cxx | 700 +++++++++++++----- .../TPC/workflow/src/tpc-miptrack-filter.cxx | 8 +- .../workflow/src/tpc-refitter-workflow.cxx | 18 +- 31 files changed, 1571 insertions(+), 313 deletions(-) create mode 100644 Detectors/TPC/calibration/include/TPCCalibration/DigitAdd.h create mode 100644 Detectors/TPC/calibration/src/DigitAdd.cxx diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h index ace488b652559..482c577ec9083 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h @@ -109,6 +109,12 @@ class CalibdEdxCorrection /// Single fit parameters averaged over all sectors for a stack type float getMeanParam(const GEMstack stack, ChargeType charge, uint32_t param) const; + /// Single fit parameters averaged over all sectors for a stack type + float getMeanEntries(ChargeType charge) const; + + /// Single fit parameters averaged over all sectors for a stack type + float getMeanEntries(const GEMstack stack, ChargeType charge) const; + #endif private: diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackCuts.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackCuts.h index f8bcc601cf659..451acfe9d1fa0 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackCuts.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackCuts.h @@ -46,13 +46,16 @@ class TrackCuts void setNClusMin(float NClusMin) { mNClusMin = NClusMin; } void setdEdxMin(float dEdxMin) { mdEdxMin = dEdxMin; } void setdEdxMax(float dEdxMax) { mdEdxMax = dEdxMax; } + /// try to remove looper cutting on (abs(z_out) - abs(z_in)) < -10), not very precise + void setCutLooper(bool cut) { mCutLooper = cut; } private: - float mPMin{0}; ///< min momentum allowed - float mPMax{1e10}; ///< max momentum allowed - float mNClusMin{0}; ///< min number of clusters in track allowed - float mdEdxMin{0}; ///< min dEdx - float mdEdxMax{1e10}; ///< max dEdx + float mPMin{0}; ///< min momentum allowed + float mPMax{1e10}; ///< max momentum allowed + float mNClusMin{0}; ///< min number of clusters in track allowed + float mdEdxMin{0}; ///< min dEdx + float mdEdxMax{1e10}; ///< max dEdx + bool mCutLooper{false}; ///< cut looper comparing zout-zin ClassDefNV(TrackCuts, 1) }; diff --git a/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx b/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx index 28a44f15cf18c..1a66eb962cdf0 100644 --- a/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx +++ b/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx @@ -135,3 +135,23 @@ float CalibdEdxCorrection::getMeanParam(const GEMstack stack, ChargeType charge, return mean / (SECTORSPERSIDE * SIDES); } + +float CalibdEdxCorrection::getMeanEntries(ChargeType charge) const +{ + float mean{}; + for (int index = 0; index < FitSize / 2; ++index) { + mean += mEntries[index + charge * FitSize / 2]; + } + + return mean / (0.5f * FitSize); +} + +float CalibdEdxCorrection::getMeanEntries(const GEMstack stack, ChargeType charge) const +{ + float mean{}; + for (int index = 0; index < SECTORSPERSIDE * SIDES; ++index) { + mean += getEntries(StackID{index, stack}, charge); + } + + return mean / (SECTORSPERSIDE * SIDES); +} diff --git a/DataFormats/Detectors/TPC/src/TrackCuts.cxx b/DataFormats/Detectors/TPC/src/TrackCuts.cxx index 43039e25734b0..111f3c3da8920 100644 --- a/DataFormats/Detectors/TPC/src/TrackCuts.cxx +++ b/DataFormats/Detectors/TPC/src/TrackCuts.cxx @@ -49,5 +49,8 @@ bool TrackCuts::goodTrack(o2::tpc::TrackTPC const& track) if (dEdx < mdEdxMin) { return false; } + if ((std::abs(track.getOuterParam().getZ()) - std::abs(track.getZ())) < -10) { + return false; + } return true; } diff --git a/Detectors/Base/include/DetectorsBase/DPLWorkflowUtils.h b/Detectors/Base/include/DetectorsBase/DPLWorkflowUtils.h index 6249b9c693b8c..ba3dd821fa118 100644 --- a/Detectors/Base/include/DetectorsBase/DPLWorkflowUtils.h +++ b/Detectors/Base/include/DetectorsBase/DPLWorkflowUtils.h @@ -25,6 +25,7 @@ #include "Framework/CompletionPolicy.h" #include "Framework/CompletionPolicyHelpers.h" #include "Framework/DeviceSpec.h" +#include "Framework/Task.h" #include "Framework/DataSpecUtils.h" #include #include diff --git a/Detectors/TPC/base/include/TPCBase/CRUCalibHelpers.h b/Detectors/TPC/base/include/TPCBase/CRUCalibHelpers.h index 464a5eb24d4f7..818a9a41d0dcc 100644 --- a/Detectors/TPC/base/include/TPCBase/CRUCalibHelpers.h +++ b/Detectors/TPC/base/include/TPCBase/CRUCalibHelpers.h @@ -20,6 +20,7 @@ #include #include #include +#include namespace fs = std::filesystem; #include "Rtypes.h" @@ -246,7 +247,9 @@ o2::tpc::CalDet getCalPad(const std::string_view fileName, const std::str return calPad; } -std::unordered_map preparePedestalFiles(const CalPad& pedestals, const CalPad& noise, float sigmaNoise = 3, float minADC = 2, float pedestalOffset = 0, bool onlyFilled = false, bool maskBad = true, float noisyChannelThreshold = 1.5, float sigmaNoiseNoisyChannels = 4, float badChannelThreshold = 6, bool fixedSize = false); +/// \param sigmaNoiseROCType can be either one value for all ROC types, or {IROC, OROC}, or {IROC, OROC1, OROC2, OROC3} +/// \param minADCROCType can be either one value for all ROC types, or {IROC, OROC}, or {IROC, OROC1, OROC2, OROC3} +std::unordered_map preparePedestalFiles(const CalPad& pedestals, const CalPad& noise, std::vector sigmaNoiseROCType = {3, 3, 3, 3}, std::vector minADCROCType = {2, 2, 2, 2}, float pedestalOffset = 0, bool onlyFilled = false, bool maskBad = true, float noisyChannelThreshold = 1.5, float sigmaNoiseNoisyChannels = 4, float badChannelThreshold = 6, bool fixedSize = false); } // namespace o2::tpc::cru_calib_helpers diff --git a/Detectors/TPC/base/include/TPCBase/Utils.h b/Detectors/TPC/base/include/TPCBase/Utils.h index b72c2a20fb45f..fbeb51f8bee69 100644 --- a/Detectors/TPC/base/include/TPCBase/Utils.h +++ b/Detectors/TPC/base/include/TPCBase/Utils.h @@ -17,6 +17,7 @@ /// \author Jens Wiechula, Jens.Wiechula@ikf.uni-frankfurt.de /// +#include #include #include @@ -44,9 +45,9 @@ namespace utils const std::vector tokenize(const std::string_view input, const std::string_view pattern); TH1* getBinInfoXY(int& binx, int& biny, float& bincx, float& bincy); void addFECInfo(); -void saveCanvases(TObjArray& arr, std::string_view outDir, std::string_view types = "png,pdf", std::string_view rootFileName = ""); -void saveCanvases(std::vector& canvases, std::string_view outDir, std::string_view types = "png,pdf", std::string_view rootFileName = ""); -void saveCanvas(TCanvas& c, std::string_view outDir, std::string_view types); +void saveCanvases(TObjArray& arr, std::string_view outDir, std::string_view types = "png,pdf", std::string_view rootFileName = "", std::string nameAdd = ""); +void saveCanvases(std::vector& canvases, std::string_view outDir, std::string_view types = "png,pdf", std::string_view rootFileName = "", std::string nameAdd = ""); +void saveCanvas(TCanvas& c, std::string_view outDir, std::string_view types, std::string nameAdd = ""); std::vector readCalPads(const std::string_view fileName, const std::vector& calPadNames); std::vector readCalPads(const std::string_view fileName, const std::string_view calPadNames); @@ -69,6 +70,19 @@ void mergeCalPads(std::string_view outputFileName, std::string_view inputFileNam /// \param treeTitle title of the tree TChain* buildChain(std::string_view command, std::string_view treeName, std::string_view treeTitle = "", bool checkSubDir = false); +template +std::string elementsToString(Iterator begin, Iterator end, const std::string separator = ", ") +{ + return std::accumulate(std::next(begin), end, std::to_string(*begin), + [&separator](auto s, auto f) { return std::move(s) + separator + std::to_string(f); }); +} + +template +std::string elementsToString(const T& val, const std::string separator = ", ") +{ + return elementsToString(val.begin(), val.end(), separator); +} + } // namespace utils } // namespace o2::tpc diff --git a/Detectors/TPC/base/src/CRUCalibHelpers.cxx b/Detectors/TPC/base/src/CRUCalibHelpers.cxx index 2a0b23b6470b4..f18baa6571f66 100644 --- a/Detectors/TPC/base/src/CRUCalibHelpers.cxx +++ b/Detectors/TPC/base/src/CRUCalibHelpers.cxx @@ -12,7 +12,9 @@ #include #include #include +#include +#include "TPCBase/Utils.h" #include "TROOT.h" #include "Framework/Logger.h" @@ -102,10 +104,26 @@ void cru_calib_helpers::debugDiff(std::string_view file1, std::string_view file2 } } -std::unordered_map cru_calib_helpers::preparePedestalFiles(const CalPad& pedestals, const CalPad& noise, float sigmaNoise, float minADC, float pedestalOffset, bool onlyFilled, bool maskBad, float noisyChannelThreshold, float sigmaNoiseNoisyChannels, float badChannelThreshold, bool fixedSize) +std::unordered_map cru_calib_helpers::preparePedestalFiles(const CalPad& pedestals, const CalPad& noise, std::vector sigmaNoiseROCType, std::vector minADCROCType, float pedestalOffset, bool onlyFilled, bool maskBad, float noisyChannelThreshold, float sigmaNoiseNoisyChannels, float badChannelThreshold, bool fixedSize) { const auto& mapper = Mapper::instance(); + auto expandVector = [](std::vector& vec, const std::string name) { + if (vec.size() == 1) { + vec.resize(4); + std::fill_n(&vec[1], 3, vec[0]); + } else if (vec.size() == 2) { + vec.resize(4); + std::fill_n(&vec[2], 2, vec[1]); + } else if (vec.size() != 4) { + LOGP(fatal, "{} definition must be either one value for all ROC types, or {{IROC, OROC}}, or {{IROC, OROC1, OROC2, OROC3}}", name); + } + LOGP(info, "Using {} = {{{}}}", name, utils::elementsToString(vec)); + }; + + expandVector(sigmaNoiseROCType, "sigmaNoiseROCType"); + expandVector(minADCROCType, "minADCROCType"); + std::unordered_map pedestalsThreshold; pedestalsThreshold["Pedestals"] = CalPad("Pedestals"); pedestalsThreshold["ThresholdMap"] = CalPad("ThresholdMap"); @@ -147,6 +165,9 @@ std::unordered_map cru_calib_helpers::preparePedestalFiles( const int fecInPartition = fecInfo.getIndex() - partInfo.getSectorFECOffset(); // const int dataWrapperID = fecInPartition >= fecOffset; // const int globalLinkID = (fecInPartition % fecOffset) + dataWrapperID * 12; + const int rocType = roc.isIROC() ? 0 : cru.partition() - 1; + const float sigmaNoise = sigmaNoiseROCType[rocType]; + const float minADC = minADCROCType[rocType]; const auto traceLength = traceLengths[ipad]; @@ -174,6 +195,7 @@ std::unordered_map cru_calib_helpers::preparePedestalFiles( float threshold = (noise > 0) ? std::max(sigmaNoise * noise, minADC) : 0; threshold = std::min(threshold, 1023.f); float thresholdHighNoise = (noiseCorr > noisyChannelThreshold) ? std::max(sigmaNoiseNoisyChannels * noise, minADC) : threshold; + thresholdHighNoise = std::min(thresholdHighNoise, 1023.f); float pedestalHighNoise = pedestal; if (noiseCorr > badChannelThreshold) { diff --git a/Detectors/TPC/base/src/Utils.cxx b/Detectors/TPC/base/src/Utils.cxx index 5ddd649166b43..8879e8ab342d2 100644 --- a/Detectors/TPC/base/src/Utils.cxx +++ b/Detectors/TPC/base/src/Utils.cxx @@ -133,11 +133,11 @@ void utils::addFECInfo() h->SetTitle(title.data()); } -void utils::saveCanvases(TObjArray& arr, std::string_view outDir, std::string_view types, std::string_view rootFileName) +void utils::saveCanvases(TObjArray& arr, std::string_view outDir, std::string_view types, std::string_view rootFileName, std::string nameAdd) { if (types.size()) { for (auto c : arr) { - utils::saveCanvas(*static_cast(c), outDir, types); + utils::saveCanvas(*static_cast(c), outDir, types, nameAdd); } } @@ -148,24 +148,24 @@ void utils::saveCanvases(TObjArray& arr, std::string_view outDir, std::string_vi } } -void utils::saveCanvases(std::vector& canvases, std::string_view outDir, std::string_view types, std::string_view rootFileName) +void utils::saveCanvases(std::vector& canvases, std::string_view outDir, std::string_view types, std::string_view rootFileName, std::string nameAdd) { TObjArray arr; for (auto c : canvases) { arr.Add(c); } - saveCanvases(arr, outDir, types, rootFileName); + saveCanvases(arr, outDir, types, rootFileName, nameAdd); } -void utils::saveCanvas(TCanvas& c, std::string_view outDir, std::string_view types) +void utils::saveCanvas(TCanvas& c, std::string_view outDir, std::string_view types, std::string nameAdd) { if (!types.size()) { return; } const auto typesVec = tokenize(types, ","); for (const auto& type : typesVec) { - c.SaveAs(fmt::format("{}/{}.{}", outDir, c.GetName(), type).data()); + c.SaveAs(fmt::format("{}/{}{}.{}", outDir, c.GetName(), nameAdd, type).data()); } } diff --git a/Detectors/TPC/calibration/CMakeLists.txt b/Detectors/TPC/calibration/CMakeLists.txt index 6e53a4af40f26..4e569774c86a5 100644 --- a/Detectors/TPC/calibration/CMakeLists.txt +++ b/Detectors/TPC/calibration/CMakeLists.txt @@ -55,6 +55,7 @@ o2_add_library(TPCCalibration src/TPCScaler.cxx src/CorrMapParam.cxx src/TPCMShapeCorrection.cxx + src/DigitAdd.cxx PUBLIC_LINK_LIBRARIES O2::DataFormatsTPC O2::TPCBase O2::TPCReconstruction ROOT::Minuit Microsoft.GSL::GSL @@ -109,7 +110,8 @@ o2_target_root_dictionary(TPCCalibration include/TPCCalibration/CalculatedEdx.h include/TPCCalibration/TPCScaler.h include/TPCCalibration/CorrMapParam.h - include/TPCCalibration/TPCMShapeCorrection.h) + include/TPCCalibration/TPCMShapeCorrection.h + include/TPCCalibration/DigitAdd.h) o2_add_test_root_macro(macro/comparePedestalsAndNoise.C PUBLIC_LINK_LIBRARIES O2::TPCBase diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h index b07d00c132175..470e2c84b5b60 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h @@ -19,14 +19,15 @@ #include #include #include -#include // o2 includes +#include "CommonDataFormat/TFIDInfo.h" #include "DataFormatsTPC/TrackTPC.h" #include "DataFormatsTPC/TrackCuts.h" #include "DataFormatsTPC/Defs.h" #include "DataFormatsTPC/CalibdEdxCorrection.h" #include "DetectorsBase/Propagator.h" +#include "CommonUtils/TreeStreamRedirector.h" // boost includes #include @@ -54,6 +55,8 @@ class CalibdEdx // Float axis to store data, without under and overflow bins. using FloatAxis = boost::histogram::axis::regular; + using TFIDInfo = o2::dataformats::TFIDInfo; + // Histogram axes types using AxesType = std::tuple< FloatAxis, // dEdx @@ -66,6 +69,9 @@ class CalibdEdx using Hist = boost::histogram::histogram; + /// copy ctor + CalibdEdx(const CalibdEdx& other); + /// \param angularBins number of bins for Tgl and Snp /// \param fitSnp enable Snp correction CalibdEdx(int dEdxBins = 60, float mindEdx = 20, float maxdEdx = 90, int angularBins = 36, bool fitSnp = false); @@ -106,6 +112,13 @@ class CalibdEdx void fill(const gsl::span); void fill(const std::vector& tracks) { fill(gsl::span(tracks)); } + void fill(const TFIDInfo& tfid, const gsl::span tracks) + { + mTFID = tfid; + fill(tracks); + } + void fill(const TFIDInfo& tfid, const std::vector& tracks) { fill(tfid, gsl::span(tracks)); } + /// Add counts from another container. void merge(const CalibdEdx* other); @@ -120,6 +133,10 @@ class CalibdEdx const CalibdEdxCorrection& getCalib() const { return mCalib; } + /// calibration used during reconstruction + void setCalibrationInput(const CalibdEdxCorrection& calib) { mCalibIn = calib; } + const CalibdEdxCorrection& getCalibrationInput() const { return mCalibIn; } + /// Return the number of hist entries of the gem stack with less statistics int minStackEntries() const; @@ -136,12 +153,25 @@ class CalibdEdx /// Save the histograms to a TTree. void writeTTree(std::string_view fileName) const; + /// Enable debug output to file of the time slots calibrations outputs and dE/dx histograms + void enableDebugOutput(std::string_view fileName); + + /// Disable debug output to file. Also writes and closes stored time slots. + void disableDebugOutput(); + + /// Write debug output to file + void finalizeDebugOutput() const; + + /// \return if debug output is enabled + bool hasDebugOutput() const { return static_cast(mDebugOutputStreamer); } + constexpr static float MipScale = 1.0 / 50.0; ///< Inverse of target dE/dx value for MIPs constexpr static float scaleTgl(float tgl, GEMstack rocType) { return tgl / conf_dedx_corr::TglScale[rocType]; } constexpr static float recoverTgl(float scaledTgl, GEMstack rocType) { return scaledTgl * conf_dedx_corr::TglScale[rocType]; } private: + // ATTENTION: Adjust copy constructor bool mFitSnp{}; bool mApplyCuts{true}; ///< Wether or not to apply tracks cuts TrackCuts mCuts{0.3, 0.7, 60}; ///< MIP @@ -151,13 +181,16 @@ class CalibdEdx float mFitCut = 0.2; ///< dEdx cut value used to remove electron tracks float mFitLowCutFactor = 1.5; ///< dEdx cut multiplier for the lower dE/dx range int mFitPasses = 3; ///< number of fit passes used to remove electron tracks + TFIDInfo mTFID{}; ///< current TFID - Hist mHist; ///< dEdx multidimensional histogram - CalibdEdxCorrection mCalib{}; ///< Calibration output + Hist mHist; ///< dEdx multidimensional histogram + CalibdEdxCorrection mCalib{}; ///< Calibration output + CalibdEdxCorrection mCalibIn{}; ///< Calibration output o2::base::Propagator::MatCorrType mMatType{}; ///< material type for track propagation - ClassDefNV(CalibdEdx, 3); + std::unique_ptr mDebugOutputStreamer; ///< Debug output streamer + ClassDefNV(CalibdEdx, 4); }; } // namespace o2::tpc diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibratordEdx.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibratordEdx.h index 1b90e525cf6dc..1de0e79b1fde6 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibratordEdx.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibratordEdx.h @@ -95,13 +95,23 @@ class CalibratordEdx final : public o2::calibration::TimeSlotCalibration mFitThreshold{}; ///< Minimum entries per stack to perform sector, 1D and 2D fit bool mApplyCuts{true}; ///< Flag to enable tracks cuts std::tuple mElectronCut{}; ///< Values passed to CalibdEdx::setElectronCut diff --git a/Detectors/TPC/calibration/include/TPCCalibration/DigitAdd.h b/Detectors/TPC/calibration/include/TPCCalibration/DigitAdd.h new file mode 100644 index 0000000000000..b6e34b2fa59e9 --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/DigitAdd.h @@ -0,0 +1,39 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file DigitAdd.h +/// \brief Extension of TPC Digit adding draw query functions for simple drawing +/// \author Jens Wiechula (Jens.Wiechula@ikf.uni-frankfurt.de) + +#ifndef ALICEO2_TPC_DIGITADD_H_ +#define ALICEO2_TPC_DIGITADD_H_ + +#include "DataFormatsTPC/Digit.h" + +namespace o2::tpc +{ +/// \class Digit +class DigitAdd : public Digit +{ + public: + int sector() const; + float lx() const; + float ly() const; + float gx() const; + float gy() const; + float cpad() const; + + ClassDefNV(DigitAdd, 1) +}; + +} // namespace o2::tpc + +#endif // ALICEO2_TPC_DIGITADD_H_ diff --git a/Detectors/TPC/calibration/macro/prepareCMFiles.C b/Detectors/TPC/calibration/macro/prepareCMFiles.C index ec0abeb9fb259..dc14bc61aa793 100644 --- a/Detectors/TPC/calibration/macro/prepareCMFiles.C +++ b/Detectors/TPC/calibration/macro/prepareCMFiles.C @@ -38,6 +38,7 @@ void prepareCMFiles(const std::string_view pulserFile, std::string outputDir = " // ===| load noise and pedestal from file |=== CalDet output("CMkValues"); + CalDet outputInv("InvCMkValues"); CalDet* pulserQtot{nullptr}; const CDBInterface::CalPadMapType* calPulser = nullptr; @@ -80,7 +81,9 @@ void prepareCMFiles(const std::string_view pulserFile, std::string outputDir = " } } + DataMapF commonModeKValuesFloat; DataMapU32 commonModeKValues; + DataMapU32 commonModeInvKValues; // ===| prepare values |=== for (size_t iroc = 0; iroc < pulserQtot->getData().size(); ++iroc) { @@ -131,14 +134,32 @@ void prepareCMFiles(const std::string_view pulserFile, std::string outputDir = " // default thresholds const auto pulserValFixed = floatToFixedSize(pulserVal); + const auto pulserValFixedInv = floatToFixedSize(1. / pulserVal); + commonModeKValuesFloat[LinkInfo(cruID, globalLinkID)][hwChannel] = pulserVal; commonModeKValues[LinkInfo(cruID, globalLinkID)][hwChannel] = pulserValFixed; + commonModeInvKValues[LinkInfo(cruID, globalLinkID)][hwChannel] = pulserValFixedInv; } } const bool onlyFilled = false; + // ===| k-Values full float precision |=== + const auto outFileFloatTxt = (outputDir + "/commonMode_K_values_float.txt"); + const auto outFileFloatRoot = (outputDir + "/commonMode_K_values_float.root"); + writeValues(outFileFloatTxt, commonModeKValuesFloat, onlyFilled); + + getCalPad(outFileFloatTxt, outFileFloatRoot, "CMkValues"); + + // ===| k-Values limited precision 2I6F |=== const auto outFileTxt = (outputDir + "/commonMode_K_values.txt"); const auto outFileRoot = (outputDir + "/commonMode_K_values.root"); writeValues(outFileTxt, commonModeKValues, onlyFilled); getCalPad(outFileTxt, outFileRoot, "CMkValues"); + + // ===| inverse k-Values limited precision 2I6F |=== + const auto outFileInvTxt = (outputDir + "/commonMode_inv_K_values.txt"); + const auto outFileInvRoot = (outputDir + "/commonMode_inv_K_values.root"); + writeValues(outFileInvTxt, commonModeInvKValues, onlyFilled); + + getCalPad(outFileInvTxt, outFileInvRoot, "InvCMkValues"); } diff --git a/Detectors/TPC/calibration/macro/preparePedestalFiles.C b/Detectors/TPC/calibration/macro/preparePedestalFiles.C index fce04d9683652..0dcd02b64551a 100644 --- a/Detectors/TPC/calibration/macro/preparePedestalFiles.C +++ b/Detectors/TPC/calibration/macro/preparePedestalFiles.C @@ -11,6 +11,7 @@ #if !defined(__CLING__) || defined(__ROOTCLING__) #include +#include #include #include @@ -27,7 +28,9 @@ using namespace o2::tpc; using namespace o2::tpc::cru_calib_helpers; -void preparePedestalFiles(const std::string_view pedestalFile, std::string outputDir = "./", float sigmaNoise = 3, float minADC = 2, float pedestalOffset = 0, bool onlyFilled = false, bool maskBad = true, float noisyChannelThreshold = 1.5, float sigmaNoiseNoisyChannels = 4, float badChannelThreshold = 6) +/// \param sigmaNoiseROCType can be either one value for all ROC types, or {IROC, OROC}, or {IROC, OROC1, OROC2, OROC3} +/// \param minADCROCType can be either one value for all ROC types, or {IROC, OROC}, or {IROC, OROC1, OROC2, OROC3} +void preparePedestalFiles(const std::string_view pedestalFile, std::string outputDir = "./", std::vector sigmaNoiseROCType = {3}, std::vector minADCROCType = {2}, float pedestalOffset = 0, bool onlyFilled = false, bool maskBad = true, float noisyChannelThreshold = 1.5, float sigmaNoiseNoisyChannels = 4, float badChannelThreshold = 6) { const auto& mapper = Mapper::instance(); @@ -62,7 +65,7 @@ void preparePedestalFiles(const std::string_view pedestalFile, std::string outpu DataMapU32 pedestalValuesPhysics; DataMapU32 thresholdlValuesPhysics; - auto pedestalsThreshold = preparePedestalFiles(*calPedestal, *calNoise, sigmaNoise, minADC, pedestalOffset, onlyFilled, maskBad, noisyChannelThreshold, sigmaNoiseNoisyChannels, badChannelThreshold); + auto pedestalsThreshold = preparePedestalFiles(*calPedestal, *calNoise, sigmaNoiseROCType, minADCROCType, pedestalOffset, onlyFilled, maskBad, noisyChannelThreshold, sigmaNoiseNoisyChannels, badChannelThreshold); // ===| prepare values |=== for (size_t iroc = 0; iroc < calPedestal->getData().size(); ++iroc) { diff --git a/Detectors/TPC/calibration/macro/preparePedestalFiles.sh b/Detectors/TPC/calibration/macro/preparePedestalFiles.sh index 8cb894807b483..f4f5abc921202 100755 --- a/Detectors/TPC/calibration/macro/preparePedestalFiles.sh +++ b/Detectors/TPC/calibration/macro/preparePedestalFiles.sh @@ -9,8 +9,8 @@ required arguments optional arguments: -o, --outputDir= : set output directory for (default: ./) --m, --minADC= : minimal ADC value accepted for threshold (default: $minADC) --s, --sigmaNoise= : number of sigmas for the threshold (default: $sigmaNoise) +-m, --minADC= : minimal ADC value accepted for threshold, either one value for all ROC types, or 'IROC,OROC' or 'IROC,OROC1,OROC2,OROC3' (default: $minADC) +-s, --sigmaNoise= : number of sigmas for the threshold, either one value for all ROC types, or 'IROC,OROC' or 'IROC,OROC1,OROC2,OROC3' (default: $sigmaNoise) -p, --pedestalOffset= : pedestal offset value -f, --onlyFilled : only write links which have data -k, --noMaskZero : don't set pedetal value of missing pads to 1023 @@ -34,8 +34,8 @@ usageAndExit() { # ===| default variable values |================================================ fileInfo= outputDir="./" -minADC=2 -sigmaNoise=3 +minADC="2" +sigmaNoise="3" pedestalOffset=0 onlyFilled=0 maskZero=1 @@ -76,6 +76,6 @@ if [[ -z "$inputFile" ]]; then fi # ===| command building and execution |========================================= -cmd="root.exe -b -q -l -n -x $O2_SRC/Detectors/TPC/calibration/macro/preparePedestalFiles.C+g'(\"$inputFile\",\"$outputDir\", $sigmaNoise, $minADC, $pedestalOffset, $onlyFilled, $maskZero, $noisyThreshold, $sigmaNoiseNoisy, $badChannelThreshold)'" +cmd="root.exe -b -q -l -n -x $O2_SRC/Detectors/TPC/calibration/macro/preparePedestalFiles.C+g'(\"$inputFile\",\"$outputDir\", {$sigmaNoise}, {$minADC}, $pedestalOffset, $onlyFilled, $maskZero, $noisyThreshold, $sigmaNoiseNoisy, $badChannelThreshold)'" echo "running: $cmd" eval $cmd diff --git a/Detectors/TPC/calibration/src/CalibdEdx.cxx b/Detectors/TPC/calibration/src/CalibdEdx.cxx index 6d6aa980b9680..114081f57c2f0 100644 --- a/Detectors/TPC/calibration/src/CalibdEdx.cxx +++ b/Detectors/TPC/calibration/src/CalibdEdx.cxx @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -29,6 +30,7 @@ #include "DataFormatsTPC/TrackCuts.h" #include "Framework/Logger.h" #include "TPCBase/ParameterGas.h" +#include "TPCBase/Utils.h" // root includes #include "TFile.h" @@ -55,6 +57,28 @@ CalibdEdx::CalibdEdx(int dEdxBins, float mindEdx, float maxdEdx, int angularBins IntAxis(0, CHARGETYPES, "charge")); } +CalibdEdx::CalibdEdx(const CalibdEdx& other) +{ + mFitSnp = other.mFitSnp; + mApplyCuts = other.mApplyCuts; + mCuts = other.mCuts; + mSectorThreshold = other.mSectorThreshold; + m1DThreshold = other.m1DThreshold; + m2DThreshold = other.m2DThreshold; + mFitCut = other.mFitCut; + mFitLowCutFactor = other.mFitLowCutFactor; + mFitPasses = other.mFitPasses; + mTFID = other.mTFID; + + mHist = other.mHist; + mCalib = other.mCalib; + mCalibIn = other.mCalibIn; + + mMatType = other.mMatType; + + // debug streamer not copied on purpose +} + void CalibdEdx::fill(const TrackTPC& track) { // applying cuts @@ -64,8 +88,11 @@ void CalibdEdx::fill(const TrackTPC& track) const auto& dEdx = track.getdEdx(); const auto sideOffset = track.hasASideClustersOnly() ? 0 : SECTORSPERSIDE; - const std::array dEdxMax{dEdx.dEdxMaxIROC, dEdx.dEdxMaxOROC1, dEdx.dEdxMaxOROC2, dEdx.dEdxMaxOROC3}; - const std::array dEdxTot{dEdx.dEdxTotIROC, dEdx.dEdxTotOROC1, dEdx.dEdxTotOROC2, dEdx.dEdxTotOROC3}; + const std::vector dEdxMax{dEdx.dEdxMaxIROC, dEdx.dEdxMaxOROC1, dEdx.dEdxMaxOROC2, dEdx.dEdxMaxOROC3}; + const std::vector dEdxTot{dEdx.dEdxTotIROC, dEdx.dEdxTotOROC1, dEdx.dEdxTotOROC2, dEdx.dEdxTotOROC3}; + std::vector dEdxMaxCorr(4); // for deugging + std::vector dEdxTotCorr(4); // for deugging + // We need a copy of the track to perform propagations o2::track::TrackPar cpTrack = track; @@ -96,13 +123,43 @@ void CalibdEdx::fill(const TrackTPC& track) } } const float snp = cpTrack.getSnp(); - const float scaledTgl = scaleTgl(std::abs(cpTrack.getTgl()), roc); + const float tgl = cpTrack.getTgl(); + const float scaledTgl = scaleTgl(std::abs(tgl), roc); if (track.hasCSideClusters()) { sector += SECTORSPERSIDE; } - mHist(dEdxMax[roc] * dEdxScale, scaledTgl, snp, sector, roc, ChargeType::Max); - mHist(dEdxTot[roc] * dEdxScale, scaledTgl, snp, sector, roc, ChargeType::Tot); + // undo previously done corrections, to allow for residual corrections + // output will still be the full correction + const float corrMax = mCalibIn.getCorrection(StackID{static_cast(sector), roc}, ChargeType::Max, tgl, snp); + const float corrTot = mCalibIn.getCorrection(StackID{static_cast(sector), roc}, ChargeType::Tot, tgl, snp); + dEdxMaxCorr[roc] = corrMax; + dEdxTotCorr[roc] = corrTot; + + static bool reported = false; + if (!reported && mCalibIn.getDims() >= 0) { + const auto meanParamTot = mCalibIn.getMeanParams(ChargeType::Tot); + LOGP(info, "Undoing previously apllied corrections with mean qTot Params {}", utils::elementsToString(meanParamTot)); + reported = true; + } + + mHist(dEdxMax[roc] * dEdxScale * corrMax, scaledTgl, snp, sector, roc, ChargeType::Max); + mHist(dEdxTot[roc] * dEdxScale * corrTot, scaledTgl, snp, sector, roc, ChargeType::Tot); + } + + if (mDebugOutputStreamer) { + const float tgl = track.getTgl(); + const float p = track.getP(); + + (*mDebugOutputStreamer) << "dedx" + << "dEdxMax=" << dEdxMax + << "dEdxMaxCorr=" << dEdxMaxCorr + << "dEdxTot=" << dEdxTot + << "dEdxTotCorr=" << dEdxTotCorr + << "tgl=" << tgl + << "p=" << p + << "tfid=" << mTFID + << "\n"; } } @@ -240,7 +297,7 @@ void CalibdEdx::finalize() } LOGP(info, "Fitting {}D dE/dx correction for GEM stacks", mCalib.getDims()); - // if entries bellow minimum sector threshold, integrate all sectors + // if entries below minimum sector threshold, integrate all sectors if (mCalib.getDims() == 0 || entries >= mSectorThreshold) { fitHist(mHist, mCalib, fitter, mFitCut, mFitLowCutFactor, mFitPasses); } else { @@ -342,3 +399,22 @@ void CalibdEdx::writeTTree(std::string_view fileName) const f.Write(); f.Close(); } + +void CalibdEdx::enableDebugOutput(std::string_view fileName) +{ + mDebugOutputStreamer = std::make_unique(fileName.data(), "recreate"); +} + +void CalibdEdx::disableDebugOutput() +{ + // This will call the TreeStream destructor and write any stored data. + mDebugOutputStreamer.reset(); +} + +void CalibdEdx::finalizeDebugOutput() const +{ + if (mDebugOutputStreamer) { + LOGP(info, "Closing dump file"); + mDebugOutputStreamer->Close(); + } +} diff --git a/Detectors/TPC/calibration/src/CalibratordEdx.cxx b/Detectors/TPC/calibration/src/CalibratordEdx.cxx index f16fb6f19ebdf..15a7335ef90d3 100644 --- a/Detectors/TPC/calibration/src/CalibratordEdx.cxx +++ b/Detectors/TPC/calibration/src/CalibratordEdx.cxx @@ -10,6 +10,7 @@ // or submit itself to any jurisdiction. #include "TPCCalibration/CalibratordEdx.h" +#include #include #include @@ -40,6 +41,7 @@ void CalibratordEdx::finalizeSlot(Slot& slot) // compute calibration values from histograms CalibdEdx* container = slot.getContainer(); container->finalize(); + container->finalizeDebugOutput(); mCalibs.push_back(container->getCalib()); TFType startTF = slot.getTFStart(); @@ -61,6 +63,21 @@ void CalibratordEdx::finalizeSlot(Slot& slot) << "correction=" << calibCopy // dE/dx corretion << "\n"; } + + if (mDumpHistograms) { + const auto fileName = fmt::format("o2tpc_CalibratordEdx_Histos_{}_{}_{}_{}.root", startTime, endTime, startTF, endTF); + const auto dumpTHn = (mDumpHistograms & 0x1) == 0x1; + const auto dumpTree = (mDumpHistograms & 0x2) == 0x2; + if (dumpTree) { + container->writeTTree(fileName); + } + if (dumpTHn) { + auto f = std::make_unique(fileName.data(), dumpTree ? "update" : "recreate"); + auto hn = container->getRootHist(); + hn->Write("calibHist"); + f->Close(); + } + } } CalibratordEdx::Slot& CalibratordEdx::emplaceNewSlot(bool front, TFType tstart, TFType tend) @@ -77,6 +94,10 @@ CalibratordEdx::Slot& CalibratordEdx::emplaceNewSlot(bool front, TFType tstart, const auto [cut, iterations, cutLowFactor] = mElectronCut; container->setElectronCut(cut, iterations, cutLowFactor); container->setMaterialType(mMatType); + if (mEnableTrackDebug) { + const auto fileName = fmt::format("o2tpc_CalibratordEdx_TrackDebug_{}_{}.root", tstart, tend); + container->enableDebugOutput(fileName); + } slot.setContainer(std::move(container)); return slot; diff --git a/Detectors/TPC/calibration/src/DigitAdd.cxx b/Detectors/TPC/calibration/src/DigitAdd.cxx new file mode 100644 index 0000000000000..bb5e4c5f31c51 --- /dev/null +++ b/Detectors/TPC/calibration/src/DigitAdd.cxx @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "GPUTPCGeometry.h" +#include "TPCBase/Mapper.h" +#include "TPCBase/CRU.h" +#include "TPCCalibration/DigitAdd.h" + +using namespace o2::tpc; + +int DigitAdd::sector() const +{ + return CRU(mCRU).sector(); +} + +float DigitAdd::lx() const +{ + const GPUCA_NAMESPACE::gpu::GPUTPCGeometry gpuGeom; + return gpuGeom.Row2X(mRow); +} + +float DigitAdd::ly() const +{ + const GPUCA_NAMESPACE::gpu::GPUTPCGeometry gpuGeom; + return gpuGeom.LinearPad2Y(sector(), mRow, getPad()); +} + +float DigitAdd::gx() const +{ + const LocalPosition2D l2D{lx(), ly()}; + const auto g2D = Mapper::LocalToGlobal(l2D, Sector(sector())); + return g2D.x(); +} + +float DigitAdd::gy() const +{ + const LocalPosition2D l2D{lx(), ly()}; + const auto g2D = Mapper::LocalToGlobal(l2D, Sector(sector())); + return g2D.y(); +} + +float DigitAdd::cpad() const +{ + const GPUCA_NAMESPACE::gpu::GPUTPCGeometry gpuGeom; + return getPad() - gpuGeom.NPads(mRow) / 2.f; +} diff --git a/Detectors/TPC/calibration/src/TPCCalibrationLinkDef.h b/Detectors/TPC/calibration/src/TPCCalibrationLinkDef.h index a751dbd85f10c..097ea756d370e 100644 --- a/Detectors/TPC/calibration/src/TPCCalibrationLinkDef.h +++ b/Detectors/TPC/calibration/src/TPCCalibrationLinkDef.h @@ -117,4 +117,6 @@ #pragma link C++ class o2::tpc::TPCMShapeCorrection + ; #pragma link C++ struct o2::tpc::TPCMShape + ; #pragma link C++ struct o2::tpc::BoundaryPotentialIFC + ; +#pragma link C++ class o2::tpc::DigitAdd + ; +#pragma link C++ class std::vector < o2::tpc::DigitAdd> + ; #endif 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); + } +} diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCRefitter.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCRefitter.h index c57b147cdfd62..31a5ce756142a 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TPCRefitter.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCRefitter.h @@ -13,11 +13,7 @@ #define O2_TPC_DATA_FILTER_H #include "ReconstructionDataFormats/GlobalTrackID.h" -#include "Framework/Task.h" #include "Framework/DataProcessorSpec.h" -#include "ReconstructionDataFormats/Track.h" -#include "MathUtils/detail/Bracket.h" -#include "DataFormatsTPC/ClusterNative.h" namespace o2::tpc { @@ -27,7 +23,7 @@ struct CorrectionMapsLoaderGloOpts; namespace o2::trackstudy { /// create a processor spec -o2::framework::DataProcessorSpec getTPCRefitterSpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts); +o2::framework::DataProcessorSpec getTPCRefitterSpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, bool requestCosmics = false); } // namespace o2::trackstudy diff --git a/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx b/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx index 2447b1f3969f2..046585e8c96b6 100644 --- a/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx +++ b/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx @@ -25,9 +25,11 @@ #include "Framework/Task.h" #include "Framework/DataProcessorSpec.h" #include "Framework/ConfigParamRegistry.h" +#include "Framework/CCDBParamSpec.h" #include "TPCCalibration/CalibdEdx.h" #include "TPCWorkflow/ProcessingHelpers.h" #include "TPCBase/CDBInterface.h" +#include "TPCBase/Utils.h" #include "DetectorsBase/GRPGeomHelper.h" using namespace o2::framework; @@ -69,12 +71,21 @@ class CalibdEdxDevice : public Task void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) final { - o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj); + if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { + return; + } + if (matcher == ConcreteDataMatcher("TPC", "TIMEGAIN", 0)) { + mCalib->setCalibrationInput(*(o2::tpc::CalibdEdxCorrection*)obj); + const auto meanParamTot = mCalib->getCalibrationInput().getMeanParams(ChargeType::Tot); + LOGP(info, "Updating TimeGain with {} dimensions and mean qTot Params {}", mCalib->getCalibrationInput().getDims(), utils::elementsToString(meanParamTot)); + return; + } } void run(ProcessingContext& pc) final { o2::base::GRPGeomHelper::instance().checkUpdates(pc); + checkUpdates(pc); const auto tfcounter = o2::header::get(pc.inputs().get("tracks").header)->startTime; const auto tracks = pc.inputs().get>("tracks"); @@ -115,6 +126,15 @@ class CalibdEdxDevice : public Task output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TPC_CalibdEdx", 0}, info); } + void checkUpdates(ProcessingContext& pc) const + { + if (pc.inputs().isValid("tpctimegain")) { + pc.inputs().get("tpctimegain"); + } else { + return; + } + } + std::shared_ptr mCCDBRequest; const o2::base::Propagator::MatCorrType mMatType{}; int mDumpToFile{}; @@ -130,6 +150,8 @@ DataProcessorSpec getCalibdEdxSpec(const o2::base::Propagator::MatCorrType matTy outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TPC_CalibdEdx"}, Lifetime::Sporadic); outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TPC_CalibdEdx"}, Lifetime::Sporadic); std::vector inputs{{"tracks", "TPC", "MIPS", Lifetime::Sporadic}}; + inputs.emplace_back("tpctimegain", "TPC", "TIMEGAIN", 0, Lifetime::Condition, ccdbParamSpec(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::CalTimeGain), {}, 1)); // time-dependent + auto ccdbRequest = std::make_shared(true, // orbitResetTime false, // GRPECS=true false, // GRPLHCIF diff --git a/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx b/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx index 08b93b0b915c7..70b27443018bb 100644 --- a/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx +++ b/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx @@ -28,10 +28,12 @@ #include "Framework/Task.h" #include "Framework/DataProcessorSpec.h" #include "Framework/ConfigParamRegistry.h" +#include "Framework/CCDBParamSpec.h" #include "TPCCalibration/CalibratordEdx.h" #include "TPCWorkflow/ProcessingHelpers.h" #include "DetectorsBase/GRPGeomHelper.h" #include "TPCBase/CDBInterface.h" +#include "TPCBase/Utils.h" using namespace o2::framework; @@ -45,9 +47,11 @@ class CalibratordEdxDevice : public Task void init(framework::InitContext& ic) final { o2::base::GRPGeomHelper::instance().setRequest(mCCDBRequest); - const auto slotLength = ic.options().get("tf-per-slot"); + const auto slotLengthTF = ic.options().get("tf-per-slot"); + const auto slotLengthSeconds = ic.options().get("seconds-per-slot"); const auto maxDelay = ic.options().get("max-delay"); const auto minEntries = ic.options().get("min-entries"); + mCalibIntervalExtensionMS = ic.options().get("calib-interval-extension") * 1000l; const auto minEntriesSector = ic.options().get("min-entries-sector"); const auto minEntries1D = ic.options().get("min-entries-1d"); @@ -63,32 +67,65 @@ class CalibratordEdxDevice : public Task const auto fitSnp = ic.options().get("fit-snp"); const auto dumpData = ic.options().get("file-dump"); + const auto dumpHistograms = ic.options().get("dump-histograms"); + const auto trackDebug = ic.options().get("track-debug"); mCalibrator = std::make_unique(); mCalibrator->setHistParams(dEdxBins, mindEdx, maxdEdx, angularBins, fitSnp); mCalibrator->setApplyCuts(false); mCalibrator->setFitThresholds(minEntriesSector, minEntries1D, minEntries2D); mCalibrator->setMinEntries(minEntries); - mCalibrator->setSlotLength(slotLength); + mCalibrator->setSlotLength(slotLengthTF); + mCalibrator->setSlotLengthInSeconds(slotLengthSeconds); mCalibrator->setMaxSlotsDelay(maxDelay); mCalibrator->setElectronCut({fitThreshold, fitPasses, fitThresholdLowFactor}); mCalibrator->setMaterialType(mMatType); + mCalibrator->setDumpHistograms(dumpHistograms); + mCalibrator->setTrackDebug(trackDebug); if (dumpData) { - mCalibrator->enableDebugOutput("calibratordEdx.root"); + const auto dumpDataName = ic.options().get("file-dump-name"); + mCalibrator->enableDebugOutput(dumpDataName); } } void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) final { - o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj); + if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { + return; + } + if (matcher == ConcreteDataMatcher("TPC", "TIMEGAIN", 0)) { + mTimeGain = *(o2::tpc::CalibdEdxCorrection*)obj; + const auto meanParamTot = mTimeGain.getMeanParams(ChargeType::Tot); + LOGP(info, "Updating TimeGain with {} dimensions and mean qTot Params {}", mTimeGain.getDims(), utils::elementsToString(meanParamTot)); + return; + } } void run(ProcessingContext& pc) final { + o2::base::TFIDInfoHelper::fillTFIDInfo(pc, mCalibrator->getCurrentTFInfo()); o2::base::GRPGeomHelper::instance().checkUpdates(pc); + checkUpdates(pc); + static bool slotLengthSet = false; + if (!slotLengthSet) { + // Important, otherwise the call to getSlotForTF below will be wrong, must be called after GRPGeomHelper update to get the correct TF length + mCalibrator->checkSlotLength(); + slotLengthSet = true; + } + + auto& slotTF = mCalibrator->getSlotForTF(mCalibrator->getCurrentTFInfo().tfCounter); + auto calib = slotTF.getContainer(); + const auto stackID = StackID{0, GEMstack::IROCgem}; + const auto calibInEnties = calib->getCalibrationInput().getEntries(stackID, ChargeType::Tot); + calib->setCalibrationInput(mTimeGain); + if (calibInEnties != mTimeGain.getEntries(stackID, ChargeType::Tot)) { + const auto meanParamTot = calib->getCalibrationInput().getMeanParams(ChargeType::Tot); + LOGP(info, "Updating TimeGain with {} dimensions and mean qTot Params {} for slot with TF range {} <=TF<= {}", + calib->getCalibrationInput().getDims(), utils::elementsToString(meanParamTot), slotTF.getTFStart(), slotTF.getTFEnd()); + } + const auto tracks = pc.inputs().get>("tracks"); - o2::base::TFIDInfoHelper::fillTFIDInfo(pc, mCalibrator->getCurrentTFInfo()); LOGP(detail, "Processing TF {} with {} tracks", mCalibrator->getCurrentTFInfo().tfCounter, tracks.size()); mRunNumber = mCalibrator->getCurrentTFInfo().runNumber; mCalibrator->process(tracks); @@ -118,7 +155,7 @@ class CalibratordEdxDevice : public Task assert(calibrations.size() == intervals.size()); for (unsigned int i = 0; i < calibrations.size(); i++) { const auto& object = calibrations[i]; - o2::ccdb::CcdbObjectInfo info(CDBTypeMap.at(CDBType::CalTimeGain), std::string{}, std::string{}, std::map{{"runNumber", std::to_string(mRunNumber)}}, intervals[i].first, intervals[i].second + 1); + o2::ccdb::CcdbObjectInfo info(CDBTypeMap.at(CDBType::CalTimeGain), std::string{}, std::string{}, std::map{{"runNumber", std::to_string(mRunNumber)}}, intervals[i].first, intervals[i].second + mCalibIntervalExtensionMS + 1); auto image = o2::ccdb::CcdbApi::createObjectImage(&object, &info); LOGP(info, "Sending object {} / {} of size {} bytes, valid for {} : {} ", info.getPath(), info.getFileName(), image->size(), info.getStartValidityTimestamp(), info.getEndValidityTimestamp()); output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TPC_CalibdEdx", i}, *image.get()); // vector @@ -127,10 +164,21 @@ class CalibratordEdxDevice : public Task mCalibrator->initOutput(); // empty the outputs after they are send } + void checkUpdates(ProcessingContext& pc) const + { + if (pc.inputs().isValid("tpctimegain")) { + pc.inputs().get("tpctimegain"); + } else { + return; + } + } + std::unique_ptr mCalibrator; const o2::base::Propagator::MatCorrType mMatType{}; std::shared_ptr mCCDBRequest; - uint64_t mRunNumber{0}; ///< processed run number + uint32_t mRunNumber{0}; ///< processed run number + long mCalibIntervalExtensionMS{0}; ///< Extension of the calibration interval end in ms + o2::tpc::CalibdEdxCorrection mTimeGain{}; ///< currently valid TimeGain }; DataProcessorSpec getCalibratordEdxSpec(const o2::base::Propagator::MatCorrType matType) @@ -140,6 +188,8 @@ DataProcessorSpec getCalibratordEdxSpec(const o2::base::Propagator::MatCorrType outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TPC_CalibdEdx"}, Lifetime::Sporadic); outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TPC_CalibdEdx"}, Lifetime::Sporadic); std::vector inputs{{"tracks", "TPC", "MIPS", Lifetime::Sporadic}}; + inputs.emplace_back("tpctimegain", "TPC", "TIMEGAIN", 0, Lifetime::Condition, ccdbParamSpec(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::CalTimeGain), {}, 1)); // time-dependent + auto ccdbRequest = std::make_shared(true, // orbitResetTime true, // GRPECS=true false, // GRPLHCIF @@ -155,9 +205,11 @@ DataProcessorSpec getCalibratordEdxSpec(const o2::base::Propagator::MatCorrType outputs, adaptFromTask(ccdbRequest, matType), Options{ - {"tf-per-slot", VariantType::UInt32, 6000u, {"number of TFs per calibration time slot"}}, + {"tf-per-slot", VariantType::UInt32, 6000u, {"number of TFs per calibration time slot, is overwritten by seconds-per-slot if > 0"}}, + {"seconds-per-slot", VariantType::Int, 180, {"seconds per calibration time slot, overwrites tf-per-slot if > 0"}}, {"max-delay", VariantType::UInt32, 10u, {"number of slots in past to consider"}}, {"min-entries", VariantType::Int, 10000, {"minimum entries per stack to fit a single time slot"}}, + {"calib-interval-extension", VariantType::UInt32, 3600u, {"seconds by which to extend the calibration interval beyond the end of the time slot"}}, {"min-entries-sector", VariantType::Int, 1000, {"min entries per GEM stack to enable sector by sector correction. Below this value we only perform one fit per ROC type (IROC, OROC1, ...; no side nor sector information)."}}, {"min-entries-1d", VariantType::Int, 10000, {"minimum entries per stack to fit 1D correction"}}, @@ -172,7 +224,11 @@ DataProcessorSpec getCalibratordEdxSpec(const o2::base::Propagator::MatCorrType {"angularbins", VariantType::Int, 36, {"number of angular bins: Tgl and Snp"}}, {"fit-snp", VariantType::Bool, false, {"enable Snp correction"}}, - {"file-dump", VariantType::Bool, false, {"directly dump calibration to file"}}}}; + {"dump-histograms", VariantType::UInt32, 0u, {"dump calibration histograms bitmask: 0x1 = as THn; 0x2 as TTree"}}, + {"file-dump", VariantType::Bool, false, {"directly dump calibration to file"}}, + {"file-dump-name", VariantType::String, "calibratordEdx.root", {"name of the file dump output file"}}, + {"track-debug", VariantType::Bool, false, {"track dEdx debugging"}}, + }}; } } // namespace o2::tpc diff --git a/Detectors/TPC/workflow/src/MIPTrackFilterSpec.cxx b/Detectors/TPC/workflow/src/MIPTrackFilterSpec.cxx index 2e60ba0bc72f6..7d8d2439e7295 100644 --- a/Detectors/TPC/workflow/src/MIPTrackFilterSpec.cxx +++ b/Detectors/TPC/workflow/src/MIPTrackFilterSpec.cxx @@ -63,7 +63,8 @@ void MIPTrackFilterDevice::init(framework::InitContext& ic) const double mindEdx = ic.options().get("min-dedx"); const double maxdEdx = ic.options().get("max-dedx"); const int minClusters = std::max(10, ic.options().get("min-clusters")); - const double mSendDummy = ic.options().get("send-dummy-data"); + const auto cutLoopers = !ic.options().get("dont-cut-loopers"); + mSendDummy = ic.options().get("send-dummy-data"); mMaxTracksPerTF = ic.options().get("maxTracksPerTF"); if (mMaxTracksPerTF > 0) { mMIPTracks.reserve(mMaxTracksPerTF); @@ -87,6 +88,7 @@ void MIPTrackFilterDevice::init(framework::InitContext& ic) mCuts.setNClusMin(minClusters); mCuts.setdEdxMin(mindEdx); mCuts.setdEdxMax(maxdEdx); + mCuts.setCutLooper(cutLoopers); } void MIPTrackFilterDevice::run(ProcessingContext& pc) @@ -169,7 +171,8 @@ DataProcessorSpec getMIPTrackFilterSpec() {"processEveryNthTF", VariantType::Int, 1, {"Using only a fraction of the data: 1: Use every TF, 10: Process only every tenth TF."}}, {"maxTracksPerTF", VariantType::Int, -1, {"Maximum number of processed tracks per TF (-1 for processing all tracks)"}}, {"process-first-n-TFs", VariantType::Int, 1, {"Number of first TFs which are not sampled"}}, - {"send-dummy-data", VariantType::Bool, false, {"Send empty data in case TF is skipped"}}}}; + {"send-dummy-data", VariantType::Bool, false, {"Send empty data in case TF is skipped"}}, + {"dont-cut-loopers", VariantType::Bool, false, {"Do not cut loopers by comparing zout-zin"}}}}; } } // namespace o2::tpc diff --git a/Detectors/TPC/workflow/src/TPCRefitter.cxx b/Detectors/TPC/workflow/src/TPCRefitter.cxx index cdc4234e6a2cc..7c14c8cd7d973 100644 --- a/Detectors/TPC/workflow/src/TPCRefitter.cxx +++ b/Detectors/TPC/workflow/src/TPCRefitter.cxx @@ -9,29 +9,32 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include #include #include +#include "CommonConstants/LHCConstants.h" #include "DataFormatsGlobalTracking/RecoContainer.h" #include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "SimulationDataFormat/MCCompLabel.h" #include "TPCCalibration/VDriftHelper.h" #include "TPCCalibration/CorrectionMapsLoader.h" #include "ReconstructionDataFormats/GlobalTrackID.h" #include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "SimulationDataFormat/MCEventLabel.h" -#include "SimulationDataFormat/MCUtils.h" -#include "CommonUtils/NameConf.h" #include "Framework/ConfigParamRegistry.h" -#include "Framework/CCDBParamSpec.h" #include "Framework/ControlService.h" #include "Framework/Task.h" +#include "MathUtils/Tsallis.h" #include "DetectorsCommonDataFormats/DetID.h" +#include "ReconstructionDataFormats/TrackCosmics.h" +#include "DataFormatsTPC/Constants.h" #include "DetectorsBase/GRPGeomHelper.h" #include "TPCWorkflow/TPCRefitter.h" +#include "GPUTPCGMMergedTrackHit.h" #include "GPUO2InterfaceRefit.h" #include "TPCBase/ParameterElectronics.h" #include "CommonUtils/TreeStreamRedirector.h" #include "Steer/MCKinematicsReader.h" +#include "DetectorsRaw/HBFUtils.h" namespace o2::trackstudy { @@ -51,6 +54,15 @@ using timeEst = o2::dataformats::TimeStampWithError; class TPCRefitterSpec final : public Task { public: + enum StudyType { + TPC = 0x1, ///< TPConly + ITSTPC = 0x2, ///< TPC + ITS matched tracks + Cosmics = 0x4, ///< Cosmics + }; + enum WriterType { + Streamer = 0x1, ///< Write per track streamer information + TFVectors = 0x2, ///< Writer vectors per TF + }; TPCRefitterSpec(std::shared_ptr dr, std::shared_ptr gr, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, GTrackID::mask_t src, bool useMC) : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mUseMC(useMC) { @@ -79,23 +91,51 @@ class TPCRefitterSpec final : public Task int mTFEnd = 999999999; int mTFCount = -1; int mDCAMinNCl = 80; + int mStudyType = 0; ///< Bitmask of 'StudyType' + int mWriterType = 0; ///< Bitmask of 'WriterType' + float mSqrt{13600}; ///< centre of mass energy + float mSamplingFactor{0.1}; ///< sampling factor in case sampling is used for unbinned data bool mUseR = false; bool mEnableDCA = false; - bool mWriteTrackClusters = false; - std::unique_ptr mDBGOut; - std::unique_ptr mDBGOutCl; + int mWriteTrackClusters = 0; ///< bitmask of which cluster information to dump to the tree: 0x1 = cluster native, 0x2 = corrected cluster positions, 0x4 = uncorrected cluster positions, 0x8 occupancy info + bool mDoSampling{false}; ///< perform sampling of unbinned data + bool mDoRefit{true}; ///< perform refit of TPC track + std::vector mClusterOccupancy; ///< binned occupancy of all clusters + std::vector mITSTPCTrackOccupanyTPCTime; ///< binned occupancy for ITS-TPC matched tracks using the TPC track time + std::vector mITSTPCTrackOccupanyCombinedTime; ///< binned occupancy for ITS-TPC matched tracks using the combined track time + std::unique_ptr mDBGOutTPC; ///< per track streamer for TPC tracks + std::unique_ptr mDBGOutITSTPC; ///< per track streamer for ITS-TPC tracks + std::unique_ptr mDBGOutTPCTF; ///< per TF streamer for TPC tracks + std::unique_ptr mDBGOutITSTPCTF; ///< per TF streamer for ITS-TPC tracks + std::unique_ptr mDBGOutCosmics; ///< per track streamer for TPC tracks + std::unique_ptr mDBGOutCl; ///< TPC cluster streamer float mITSROFrameLengthMUS = 0.; GTrackID::mask_t mTracksSrc{}; - o2::steer::MCKinematicsReader mcReader; // reader of MC information + o2::steer::MCKinematicsReader mcReader; ///< reader of MC information + std::mt19937 mGenerator; ///< random generator for sampling + float mVdriftTB; ///< VDrift expressed in cm/TimeBin + float mTPCTBBias; ///< Time bin bias + uint32_t mTimeBinsPerTF{}; ///< number of time bins in TF + uint32_t mOccupancyBinsPerTF{}; ///< number of time bins in TF + uint32_t mTimeBinsPerDrift{500}; ///< number of time bins assumed in one drift + // + // Input data // - // TPC data gsl::span mTPCTrackClusIdx; ///< input TPC track cluster indices span gsl::span mTPCTracksArray; ///< input TPC tracks span + gsl::span mITSTPCTracksArray; ///< input TPC-ITS tracks span + gsl::span mITSTracksArray; ///< input ITS tracks span + gsl::span mCosmics; ///< input ITS tracks span gsl::span mTPCRefitterShMap; ///< externally set TPC clusters sharing map gsl::span mTPCRefitterOccMap; ///< externally set TPC clusters occupancy map const o2::tpc::ClusterNativeAccess* mTPCClusterIdxStruct = nullptr; ///< struct holding the TPC cluster indices gsl::span mTPCTrkLabels; ///< input TPC Track MC labels std::unique_ptr mTPCRefitter; ///< TPC refitter used for TPC tracks refit during the reconstruction + std::vector mIntRecs; + + void fillOccupancyVectors(o2::globaltracking::RecoContainer& recoData); + bool processTPCTrack(o2::tpc::TrackTPC tr, o2::MCCompLabel lbl, o2::utils::TreeStreamRedirector* streamer, const o2::its::TrackITS* its = nullptr, const o2::dataformats::TrackTPCITS* itstpc = nullptr, bool outward = false, float time0custom = -1); + void processCosmics(o2::globaltracking::RecoContainer& recoData); }; void TPCRefitterSpec::init(InitContext& ic) @@ -109,20 +149,46 @@ void TPCRefitterSpec::init(InitContext& ic) mTFEnd = ic.options().get("tf-end"); mDCAMinPt = ic.options().get("dcaMinPt"); mDCAMinNCl = ic.options().get("dcaMinNCl"); - if (mXRef < 0.) { - mXRef = 0.; + mSqrt = ic.options().get("sqrts"); + mSamplingFactor = ic.options().get("sampling-factor"); + mDoSampling = ic.options().get("do-sampling"); + mDoRefit = ic.options().get("do-refit"); + mStudyType = ic.options().get("study-type"); + mWriterType = ic.options().get("writer-type"); + mWriteTrackClusters = ic.options().get("write-track-clusters"); + const auto occBinsPerDrift = ic.options().get("occupancy-bins-per-drift"); + mTimeBinsPerTF = (o2::raw::HBFUtils::Instance().nHBFPerTF * o2::constants::lhc::LHCMaxBunches) / 8 + 2 * mTimeBinsPerDrift; // add one drift before and after the TF + mOccupancyBinsPerTF = static_cast(std::ceil(float(mTimeBinsPerTF * occBinsPerDrift) / mTimeBinsPerDrift)); + mClusterOccupancy.resize(mOccupancyBinsPerTF); + mITSTPCTrackOccupanyTPCTime.resize(mOccupancyBinsPerTF); + mITSTPCTrackOccupanyCombinedTime.resize(mOccupancyBinsPerTF); + LOGP(info, "Using {} bins for the occupancy per TF", mOccupancyBinsPerTF); + + if ((mWriterType & WriterType::Streamer) == WriterType::Streamer) { + if ((mStudyType & StudyType::TPC) == StudyType::TPC) { + mDBGOutTPC = std::make_unique("tpctracks-study-streamer.root", "recreate"); + } + if ((mStudyType & StudyType::ITSTPC) == StudyType::ITSTPC) { + mDBGOutITSTPC = std::make_unique("itstpctracks-study-streamer.root", "recreate"); + } + if ((mStudyType & StudyType::Cosmics) == StudyType::Cosmics) { + mDBGOutCosmics = std::make_unique("cosmics-study-streamer.root", "recreate"); + } } - mTPCCorrMapsLoader.init(ic); - mDBGOut = std::make_unique("tpctracks-refitted.root", "recreate"); - mWriteTrackClusters = ic.options().get("dump-clusters"); if (ic.options().get("dump-clusters")) { mDBGOutCl = std::make_unique("tpc-trackStudy-cl.root", "recreate"); } + + if (mXRef < 0.) { + mXRef = 0.; + } + mGenerator = std::mt19937(std::random_device{}()); + mTPCCorrMapsLoader.init(ic); } void TPCRefitterSpec::run(ProcessingContext& pc) { - mTFCount++; + ++mTFCount; if (mTFCount < mTFStart || mTFCount > mTFEnd) { LOGP(info, "Skipping TF {}", mTFCount); return; @@ -131,9 +197,10 @@ void TPCRefitterSpec::run(ProcessingContext& pc) o2::globaltracking::RecoContainer recoData; recoData.collectData(pc, *mDataRequest.get()); // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer updateTimeDependentParams(pc); // Make sure this is called after recoData.collectData, which may load some conditions + fillOccupancyVectors(recoData); process(recoData); - if (mTFCount > mTFEnd) { + if (mTFCount >= mTFEnd) { LOGP(info, "Stopping processing after TF {}", mTFCount); pc.services().get().endOfStream(); return; @@ -169,36 +236,109 @@ void TPCRefitterSpec::updateTimeDependentParams(ProcessingContext& pc) } } +void TPCRefitterSpec::fillOccupancyVectors(o2::globaltracking::RecoContainer& recoData) +{ + // reset counters + std::fill(mClusterOccupancy.begin(), mClusterOccupancy.end(), 0u); + std::fill(mITSTPCTrackOccupanyTPCTime.begin(), mITSTPCTrackOccupanyTPCTime.end(), 0u); + std::fill(mITSTPCTrackOccupanyCombinedTime.begin(), mITSTPCTrackOccupanyCombinedTime.end(), 0u); + + // fill cluster occupancy + const auto& clusterIndex = recoData.inputsTPCclusters->clusterIndex; + using namespace o2::tpc::constants; + for (int sector = 0; sector < MAXSECTOR; ++sector) { + for (int padrow = 0; padrow < MAXGLOBALPADROW; ++padrow) { + for (size_t icl = 0; icl < clusterIndex.nClusters[sector][padrow]; ++icl) { + const auto& cl = clusterIndex.clusters[sector][padrow][icl]; + // shift by one TPC drift to allow seeing pile-up + const auto tpcTime = cl.getTime() + mTimeBinsPerDrift; + const uint32_t clOccPos = static_cast(tpcTime * mOccupancyBinsPerTF / mTimeBinsPerTF); + if (clOccPos >= mOccupancyBinsPerTF) { + LOGP(error, "cluster with time {} outside TPC acceptanc", cl.getTime()); + } else { + ++mClusterOccupancy[clOccPos]; + } + } + } + } + + // fill track occupancy for its-tpc matched tracks + auto tpcTracks = recoData.getTPCTracks(); + auto itstpcTracks = recoData.getTPCITSTracks(); + const auto& paramEle = o2::tpc::ParameterElectronics::Instance(); + + for (const auto& tpcitsTrack : itstpcTracks) { + const auto idxTPC = tpcitsTrack.getRefTPC().getIndex(); + if (idxTPC >= tpcTracks.size()) { + LOGP(fatal, "TPC index {} out of array size {}", idxTPC, tpcTracks.size()); + } + const auto& tpcTrack = tpcTracks[idxTPC]; + // shift by one TPC drift to allow seeing pile-up + const auto tpcTime = tpcTrack.getTime0() + mTimeBinsPerDrift; + if (tpcTime >= 0) { + const uint32_t clOccPosTPC = static_cast(tpcTime * mOccupancyBinsPerTF / mTimeBinsPerTF); + if (clOccPosTPC < mITSTPCTrackOccupanyTPCTime.size()) { + ++mITSTPCTrackOccupanyTPCTime[clOccPosTPC]; + } else { + LOGP(warn, "TF {}: TPC occupancy index {} out of range {}", mTFCount, clOccPosTPC, mITSTPCTrackOccupanyTPCTime.size()); + } + } + // convert mus to time bins + // shift by one TPC drift to allow seeing pile-up + const auto tpcitsTime = tpcitsTrack.getTimeMUS().getTimeStamp() / paramEle.ZbinWidth + mTimeBinsPerDrift; + if (tpcitsTime > 0) { + const uint32_t clOccPosITSTPC = static_cast(tpcitsTime * mOccupancyBinsPerTF / mTimeBinsPerTF); + if (clOccPosITSTPC < mITSTPCTrackOccupanyCombinedTime.size()) { + ++mITSTPCTrackOccupanyCombinedTime[clOccPosITSTPC]; + } + } + } + + auto fillDebug = [this](o2::utils::TreeStreamRedirector* streamer) { + if (streamer) { + *streamer << "occupancy" + << "tfCounter=" << mTFCount + << "clusterOcc=" << mClusterOccupancy + << "tpcTrackTimeOcc=" << mITSTPCTrackOccupanyTPCTime + << "itstpcTrackTimeOcc=" << mITSTPCTrackOccupanyCombinedTime + << "\n"; + } + }; + + fillDebug(mDBGOutTPC.get()); + fillDebug(mDBGOutITSTPC.get()); +} + void TPCRefitterSpec::process(o2::globaltracking::RecoContainer& recoData) { - static long counter = -1; auto prop = o2::base::Propagator::Instance(); + mITSTracksArray = recoData.getITSTracks(); mTPCTracksArray = recoData.getTPCTracks(); + mITSTPCTracksArray = recoData.getTPCITSTracks(); + mCosmics = recoData.getCosmicTracks(); + mTPCTrackClusIdx = recoData.getTPCTracksClusterRefs(); mTPCClusterIdxStruct = &recoData.inputsTPCclusters->clusterIndex; mTPCRefitterShMap = recoData.clusterShMapTPC; mTPCRefitterOccMap = recoData.occupancyMapTPC; - std::vector intRecs; + LOGP(info, "Processing TF {} with {} its, {} tpc, {} its-tpc tracks and {} comsmics", mTFCount, mITSTracksArray.size(), mTPCTracksArray.size(), mITSTPCTracksArray.size(), mCosmics.size()); if (mUseMC) { // extract MC tracks const o2::steer::DigitizationContext* digCont = nullptr; if (!mcReader.initFromDigitContext("collisioncontext.root")) { throw std::invalid_argument("initialization of MCKinematicsReader failed"); } digCont = mcReader.getDigitizationContext(); - intRecs = digCont->getEventRecords(); + mIntRecs = digCont->getEventRecords(); mTPCTrkLabels = recoData.getTPCTracksMCLabels(); } mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, &mTPCCorrMapsLoader, prop->getNominalBz(), mTPCTrackClusIdx.data(), 0, mTPCRefitterShMap.data(), mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size(), nullptr, prop); mTPCRefitter->setTrackReferenceX(900); // disable propagation after refit by setting reference to value > 500 - float vdriftTB = mTPCVDriftHelper.getVDriftObject().getVDrift() * o2::tpc::ParameterElectronics::Instance().ZbinWidth; // VDrift expressed in cm/TimeBin - float tpcTBBias = mTPCVDriftHelper.getVDriftObject().getTimeOffset() / (8 * o2::constants::lhc::LHCBunchSpacingMUS); - std::vector clSector, clRow; - std::vector clX, clY, clZ, clXI, clYI, clZI; // *I are the uncorrected cluster positions - float dcar, dcaz, dcarRef, dcazRef; + mVdriftTB = mTPCVDriftHelper.getVDriftObject().getVDrift() * o2::tpc::ParameterElectronics::Instance().ZbinWidth; // VDrift expressed in cm/TimeBin + mTPCTBBias = mTPCVDriftHelper.getVDriftObject().getTimeOffset() / (8 * o2::constants::lhc::LHCBunchSpacingMUS); auto dumpClusters = [this] { static int tf = 0; @@ -229,190 +369,39 @@ void TPCRefitterSpec::process(o2::globaltracking::RecoContainer& recoData) dumpClusters(); } - for (size_t itr = 0; itr < mTPCTracksArray.size(); itr++) { - auto tr = mTPCTracksArray[itr]; // create track copy - if (tr.hasBothSidesClusters()) { - continue; + if ((mStudyType & StudyType::TPC) == StudyType::TPC) { + for (size_t itr = 0; itr < mTPCTracksArray.size(); itr++) { + processTPCTrack(mTPCTracksArray[itr], mUseMC ? mTPCTrkLabels[itr] : o2::MCCompLabel{}, mDBGOutTPC.get()); } + } - //========================================================================= - // create refitted copy - auto trackRefit = [itr, this](o2::track::TrackParCov& trc, float t, float chi2refit) -> bool { - int retVal = mUseGPUModel ? this->mTPCRefitter->RefitTrackAsGPU(trc, this->mTPCTracksArray[itr].getClusterRef(), t, &chi2refit, false, true) - : this->mTPCRefitter->RefitTrackAsTrackParCov(trc, this->mTPCTracksArray[itr].getClusterRef(), t, &chi2refit, false, true); - if (retVal < 0) { - LOGP(warn, "Refit failed ({}) with time={}: track#{}[{}]", retVal, t, counter, trc.asString()); - return false; - } - return true; - }; - - auto trackProp = [&tr, itr, prop, this](o2::track::TrackParCov& trc) -> bool { - if (!trc.rotate(tr.getAlpha())) { - LOGP(warn, "Rotation to original track alpha {} failed, track#{}[{}]", tr.getAlpha(), counter, trc.asString()); - return false; - } - float xtgt = this->mXRef; - if (mUseR && !trc.getXatLabR(this->mXRef, xtgt, prop->getNominalBz(), o2::track::DirInward)) { - xtgt = 0; - return false; - } - if (!prop->PropagateToXBxByBz(trc, xtgt)) { - LOGP(warn, "Propagation to X={} failed, track#{}[{}]", xtgt, counter, trc.asString()); - return false; - } - return true; - }; - - auto prepClus = [this, &tr, &clSector, &clRow, &clX, &clY, &clZ, &clXI, &clYI, &clZI](float t) { // extract cluster info - clSector.clear(); - clRow.clear(); - clXI.clear(); - clYI.clear(); - clZI.clear(); - clX.clear(); - clY.clear(); - clZ.clear(); - int count = tr.getNClusters(); - const auto* corrMap = this->mTPCCorrMapsLoader.getCorrMap(); - const o2::tpc::ClusterNative* cl = nullptr; - for (int ic = count; ic--;) { - uint8_t sector, row; - cl = &tr.getCluster(this->mTPCTrackClusIdx, ic, *this->mTPCClusterIdxStruct, sector, row); - clSector.push_back(sector); - clRow.push_back(row); - float x, y, z; - // ideal transformation without distortions - corrMap->TransformIdeal(sector, row, cl->getPad(), cl->getTime(), x, y, z, t); // nominal time of the track - clXI.push_back(x); - clYI.push_back(y); - clZI.push_back(z); - - // transformation without distortions - mTPCCorrMapsLoader.Transform(sector, row, cl->getPad(), cl->getTime(), x, y, z, t); // nominal time of the track - clX.push_back(x); - clY.push_back(y); - clZ.push_back(z); + if ((mStudyType & StudyType::ITSTPC) == StudyType::ITSTPC) { + for (const auto& tpcitsTrack : mITSTPCTracksArray) { + const auto idxTPC = tpcitsTrack.getRefTPC().getIndex(); + const auto idxITS = tpcitsTrack.getRefITS().getIndex(); + if (idxITS >= mITSTracksArray.size()) { + LOGP(fatal, "ITS index {} out of array size {}", idxITS, mITSTracksArray.size()); } - }; - - //========================================================================= - - auto trf = tr.getOuterParam(); // we refit inward original track - float chi2refit = 0; - if (!trackRefit(trf, tr.getTime0(), chi2refit) || !trackProp(trf)) { - continue; - } - - // propagate original track - if (!trackProp(tr)) { - continue; - } - - if (mWriteTrackClusters) { - prepClus(tr.getTime0()); // original clusters - } - - if (mEnableDCA) { - dcar = dcaz = dcarRef = dcazRef = 9999.f; - if ((trf.getPt() > mDCAMinPt) && (tr.getNClusters() > mDCAMinNCl)) { - getDCAs(trf, dcarRef, dcazRef); - getDCAs(tr, dcar, dcaz); + if (idxTPC >= mTPCTracksArray.size()) { + LOGP(fatal, "TPC index {} out of array size {}", idxTPC, mTPCTracksArray.size()); } + processTPCTrack(mTPCTracksArray[idxTPC], mUseMC ? mTPCTrkLabels[idxTPC] : o2::MCCompLabel{}, mDBGOutITSTPC.get(), &mITSTracksArray[idxITS], &tpcitsTrack); } + } - counter++; - // store results - (*mDBGOut) << "tpcIni" - << "counter=" << counter - << "iniTrack=" << tr - << "iniTrackRef=" << trf - << "time=" << tr.getTime0() - << "chi2refit=" << chi2refit; - - if (mWriteTrackClusters) { - (*mDBGOut) << "tpcIni" - << "clSector=" << clSector - << "clRow=" << clRow - << "clX=" << clX - << "clY=" << clY - << "clZ=" << clZ - << "clXI=" << clXI // ideal (uncorrected) cluster positions - << "clYI=" << clYI // ideal (uncorrected) cluster positions - << "clZI=" << clZI; // ideal (uncorrected) cluster positions - } - - if (mEnableDCA) { - (*mDBGOut) << "tpcIni" - << "dcar=" << dcar - << "dcaz=" << dcaz - << "dcarRef=" << dcarRef - << "dcazRef=" << dcazRef; - } - - (*mDBGOut) << "tpcIni" - << "\n"; - - float dz = 0; - - if (mUseMC) { // impose MC time in TPC timebin and refit inward after resetted covariance - // extract MC truth - const o2::MCTrack* mcTrack = nullptr; - auto lbl = mTPCTrkLabels[itr]; - if (!lbl.isValid() || !(mcTrack = mcReader.getTrack(lbl))) { - break; - } - long bc = intRecs[lbl.getEventID()].toLong(); // bunch crossing of the interaction - float bcTB = bc / 8. + tpcTBBias; // the same in TPC timebins, accounting for the TPC time bias - // create MC truth track in O2 format - std::array xyz{(float)mcTrack->GetStartVertexCoordinatesX(), (float)mcTrack->GetStartVertexCoordinatesY(), (float)mcTrack->GetStartVertexCoordinatesZ()}, - pxyz{(float)mcTrack->GetStartVertexMomentumX(), (float)mcTrack->GetStartVertexMomentumY(), (float)mcTrack->GetStartVertexMomentumZ()}; - TParticlePDG* pPDG = TDatabasePDG::Instance()->GetParticle(mcTrack->GetPdgCode()); - if (!pPDG) { - break; - } - o2::track::TrackPar mctrO2(xyz, pxyz, TMath::Nint(pPDG->Charge() / 3), false); - // - // propagate it to the alpha/X of the reconstructed track - if (!mctrO2.rotate(tr.getAlpha()) || !prop->PropagateToXBxByBz(mctrO2, tr.getX())) { - break; - } - // now create a properly refitted track with correct time and distortions correction - { - auto trfm = tr.getOuterParam(); // we refit inward - // impose MC time in TPC timebin and refit inward after resetted covariance - float chi2refit = 0; - if (!trackRefit(trfm, bcTB, chi2refit) || !trfm.rotate(tr.getAlpha()) || !prop->PropagateToXBxByBz(trfm, tr.getX())) { - LOGP(warn, "Failed to propagate MC-time refitted track#{} [{}] to X/alpha of original track [{}]", counter, trfm.asString(), tr.asString()); - break; - } - // estimate Z shift in case of no-distortions - dz = (tr.getTime0() - bcTB) * vdriftTB; - if (tr.hasCSideClustersOnly()) { - dz = -dz; - } - // - prepClus(bcTB); // clusters for MC time - (*mDBGOut) << "tpcMC" - << "counter=" << counter - << "movTrackRef=" << trfm - << "mcTrack=" << mctrO2 - << "imposedTB=" << bcTB - << "chi2refit=" << chi2refit - << "dz=" << dz - << "clX=" << clX - << "clY=" << clY - << "clZ=" << clZ - << "\n"; - } - break; - } + if (mCosmics.size() > 0) { + LOGP(info, "Procssing {} cosmics", mCosmics.size()); + processCosmics(recoData); } } void TPCRefitterSpec::endOfStream(EndOfStreamContext& ec) { - mDBGOut.reset(); + mDBGOutTPC.reset(); + mDBGOutITSTPC.reset(); + mDBGOutTPCTF.reset(); + mDBGOutITSTPCTF.reset(); + mDBGOutCosmics.reset(); mDBGOutCl.reset(); } @@ -445,25 +434,336 @@ bool TPCRefitterSpec::getDCAs(const o2::track::TrackPar& track, float& dcar, flo return ok; } -DataProcessorSpec getTPCRefitterSpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts) +bool TPCRefitterSpec::processTPCTrack(o2::tpc::TrackTPC tr, o2::MCCompLabel lbl, o2::utils::TreeStreamRedirector* streamer, const o2::its::TrackITS* its, const o2::dataformats::TrackTPCITS* itstpc, bool outward, float time0custom) +{ + auto prop = o2::base::Propagator::Instance(); + static long counter = -1; + + struct ClusterData { + std::vector occCl; + std::vector clSector, clRow; + std::vector clX, clY, clZ, clXI, clYI, clZI; // *I are the uncorrected cluster positions + std::vector clNative; + } clData; + float dcar, dcaz, dcarRef, dcazRef; + + // auto tr = mTPCTracksArray[itr]; // create track copy + if (tr.hasBothSidesClusters()) { + return false; + } + + bool sampleTsallis = false; + bool sampleMB = false; + float tsallisWeight = 0; + if (mDoSampling) { + std::uniform_real_distribution<> distr(0., 1.); + if (o2::math_utils::Tsallis::downsampleTsallisCharged(tr.getPt(), mSamplingFactor, mSqrt, tsallisWeight, distr(mGenerator))) { + sampleTsallis = true; + } + if (distr(mGenerator) < mSamplingFactor) { + sampleMB = true; + } + + if (!sampleMB && !sampleTsallis) { + return false; + } + } + //========================================================================= + // create refitted copy + auto trackRefit = [&tr, this](o2::track::TrackParCov& trc, float t, float chi2refit, bool outward = false) -> bool { + int retVal = mUseGPUModel ? this->mTPCRefitter->RefitTrackAsGPU(trc, tr.getClusterRef(), t, &chi2refit, outward, true) + : this->mTPCRefitter->RefitTrackAsTrackParCov(trc, tr.getClusterRef(), t, &chi2refit, outward, true); + if (retVal < 0) { + LOGP(warn, "Refit failed ({}) with time={}: track#{}[{}]", retVal, t, counter, trc.asString()); + return false; + } + return true; + }; + + auto trackProp = [&tr, prop, this](o2::track::TrackParCov& trc) -> bool { + if (!trc.rotate(tr.getAlpha())) { + LOGP(warn, "Rotation to original track alpha {} failed, track#{}[{}]", tr.getAlpha(), counter, trc.asString()); + return false; + } + float xtgt = this->mXRef; + if (mUseR && !trc.getXatLabR(this->mXRef, xtgt, prop->getNominalBz(), o2::track::DirInward)) { + xtgt = 0; + return false; + } + if (!prop->PropagateToXBxByBz(trc, xtgt)) { + LOGP(warn, "Propagation to X={} failed, track#{}[{}]", xtgt, counter, trc.asString()); + return false; + } + return true; + }; + + // auto prepClus = [this, &tr, &clSector, &clRow, &clX, &clY, &clZ, &clXI, &clYI, &clZI, &clNative](float t) { // extract cluster info + auto prepClus = [this, &tr, &clData](float t) { // extract cluster info + int count = tr.getNClusters(); + const auto* corrMap = this->mTPCCorrMapsLoader.getCorrMap(); + const o2::tpc::ClusterNative* cl = nullptr; + for (int ic = count; ic--;) { + uint8_t sector, row; + uint32_t clusterIndex; + o2::tpc::TrackTPC::getClusterReference(mTPCTrackClusIdx, ic, sector, row, clusterIndex, tr.getClusterRef()); + unsigned int absoluteIndex = mTPCClusterIdxStruct->clusterOffset[sector][row] + clusterIndex; + cl = &mTPCClusterIdxStruct->clusters[sector][row][clusterIndex]; + uint8_t clflags = cl->getFlags(); + if (mTPCRefitterShMap[absoluteIndex] & GPUCA_NAMESPACE::gpu::GPUTPCGMMergedTrackHit::flagShared) { + clflags |= 0x10; + } + clData.clSector.emplace_back(sector); + clData.clRow.emplace_back(row); + auto& clCopy = clData.clNative.emplace_back(*cl); + clCopy.setFlags(clflags); + + float x, y, z; + // ideal transformation without distortions + corrMap->TransformIdeal(sector, row, cl->getPad(), cl->getTime(), x, y, z, t); // nominal time of the track + clData.clXI.emplace_back(x); + clData.clYI.emplace_back(y); + clData.clZI.emplace_back(z); + + // transformation without distortions + mTPCCorrMapsLoader.Transform(sector, row, cl->getPad(), cl->getTime(), x, y, z, t); // nominal time of the track + clData.clX.emplace_back(x); + clData.clY.emplace_back(y); + clData.clZ.emplace_back(z); + + // occupancy estimator + const auto tpcTime = cl->getTime() + mTimeBinsPerDrift; + const uint32_t clOccPosTPC = static_cast(tpcTime * mOccupancyBinsPerTF / mTimeBinsPerTF); + clData.occCl.emplace_back((clOccPosTPC < mClusterOccupancy.size()) ? mClusterOccupancy[clOccPosTPC] : -1); + } + }; + + //========================================================================= + + auto trf = tr.getOuterParam(); // we refit inward original track + float chi2refit = 0; + float time0 = tr.getTime0(); + if (time0custom > 0) { + time0 = time0custom; + } + if (mDoRefit) { + if (!trackRefit(trf, time0, chi2refit) || !trackProp(trf)) { + return false; + } + } + + // propagate original track + if (!trackProp(tr)) { + return false; + } + + if (mWriteTrackClusters) { + prepClus(time0); // original clusters + } + + if (mEnableDCA) { + dcar = dcaz = dcarRef = dcazRef = 9999.f; + if ((trf.getPt() > mDCAMinPt) && (tr.getNClusters() > mDCAMinNCl)) { + getDCAs(trf, dcarRef, dcazRef); + getDCAs(tr, dcar, dcaz); + } + } + + counter++; + // store results + if (streamer) { + (*streamer) << "tpc" + << "counter=" << counter + << "tfCounter=" << mTFCount + << "tpc=" << tr; + + if (mDoRefit) { + (*streamer) << "tpc" + << "tpcRF=" << trf + << "time0=" << time0 + << "chi2refit=" << chi2refit; + } + + if (mDoSampling) { + (*streamer) << "tpc" + << "tsallisWeight=" << tsallisWeight + << "sampleTsallis=" << sampleTsallis + << "sampleMB=" << sampleMB; + } + + if (mWriteTrackClusters) { + (*streamer) << "tpc" + << "clSector=" << clData.clSector + << "clRow=" << clData.clRow; + + if ((mWriteTrackClusters & 0x1) == 0x1) { + (*streamer) << "tpc" + << "cl=" << clData.clNative; + } + + if ((mWriteTrackClusters & 0x2) == 0x2) { + (*streamer) << "tpc" + << "clX=" << clData.clX + << "clY=" << clData.clY + << "clZ=" << clData.clZ; + } + + if ((mWriteTrackClusters & 0x4) == 0x4) { + (*streamer) << "tpc" + << "clXI=" << clData.clXI // ideal (uncorrected) cluster positions + << "clYI=" << clData.clYI // ideal (uncorrected) cluster positions + << "clZI=" << clData.clZI; // ideal (uncorrected) cluster positions + } + + if ((mWriteTrackClusters & 0x8) == 0x8) { + (*streamer) << "tpc" + << "clOcc=" << clData.occCl; + } + } + + if (its) { + (*streamer) << "tpc" + << "its=" << *its; + } + if (itstpc) { + (*streamer) << "tpc" + << "itstpc=" << *itstpc; + } + + if (mEnableDCA) { + (*streamer) << "tpc" + << "dcar=" << dcar + << "dcaz=" << dcaz + << "dcarRef=" << dcarRef + << "dcazRef=" << dcazRef; + } + + (*streamer) << "tpc" + << "\n"; + } + + float dz = 0; + + if (mUseMC) { // impose MC time in TPC timebin and refit inward after resetted covariance + // extract MC truth + const o2::MCTrack* mcTrack = nullptr; + if (!lbl.isValid() || !(mcTrack = mcReader.getTrack(lbl))) { + return false; + } + long bc = mIntRecs[lbl.getEventID()].toLong(); // bunch crossing of the interaction + float bcTB = bc / 8. + mTPCTBBias; // the same in TPC timebins, accounting for the TPC time bias + // create MC truth track in O2 format + std::array xyz{(float)mcTrack->GetStartVertexCoordinatesX(), (float)mcTrack->GetStartVertexCoordinatesY(), (float)mcTrack->GetStartVertexCoordinatesZ()}, + pxyz{(float)mcTrack->GetStartVertexMomentumX(), (float)mcTrack->GetStartVertexMomentumY(), (float)mcTrack->GetStartVertexMomentumZ()}; + TParticlePDG* pPDG = TDatabasePDG::Instance()->GetParticle(mcTrack->GetPdgCode()); + if (!pPDG) { + return false; + } + o2::track::TrackPar mctrO2(xyz, pxyz, TMath::Nint(pPDG->Charge() / 3), false); + // + // propagate it to the alpha/X of the reconstructed track + if (!mctrO2.rotate(tr.getAlpha()) || !prop->PropagateToXBxByBz(mctrO2, tr.getX())) { + return false; + } + // now create a properly refitted track with correct time and distortions correction + { + auto trfm = tr.getOuterParam(); // we refit inward + // impose MC time in TPC timebin and refit inward after resetted covariance + float chi2refit = 0; + if (!trackRefit(trfm, bcTB, chi2refit) || !trfm.rotate(tr.getAlpha()) || !prop->PropagateToXBxByBz(trfm, tr.getX())) { + LOGP(warn, "Failed to propagate MC-time refitted track#{} [{}] to X/alpha of original track [{}]", counter, trfm.asString(), tr.asString()); + return false; + } + // estimate Z shift in case of no-distortions + dz = (tr.getTime0() - bcTB) * mVdriftTB; + if (tr.hasCSideClustersOnly()) { + dz = -dz; + } + // + prepClus(bcTB); // clusters for MC time + if (streamer) { + (*streamer) << "tpcMC" + << "counter=" << counter + << "movTrackRef=" << trfm + << "mcTrack=" << mctrO2 + << "imposedTB=" << bcTB + << "chi2refit=" << chi2refit + << "dz=" << dz + << "clX=" << clData.clX + << "clY=" << clData.clY + << "clZ=" << clData.clZ + << "\n"; + } + } + return false; + } + + return true; +} + +void TPCRefitterSpec::processCosmics(o2::globaltracking::RecoContainer& recoData) +{ + auto tof = recoData.getTOFClusters(); + const auto& par = o2::tpc::ParameterElectronics::Instance(); + const auto invBinWidth = 1.f / par.ZbinWidth; + + for (const auto& cosmic : mCosmics) { + // + const auto& gidtop = cosmic.getRefTop(); + const auto& gidbot = cosmic.getRefBottom(); + + // LOGP(info, "Sources: {} - {}", o2::dataformats::GlobalTrackID::getSourceName(gidtop.getSource()), o2::dataformats::GlobalTrackID::getSourceName(gidbot.getSource())); + + std::array contributorsGID[2] = {recoData.getSingleDetectorRefs(cosmic.getRefTop()), recoData.getSingleDetectorRefs(cosmic.getRefBottom())}; + const auto trackTime = cosmic.getTimeMUS().getTimeStamp() * invBinWidth; + + // check if track has TPC & TOF for top and bottom part + // loop over both parts + for (const auto& comsmicInfo : contributorsGID) { + auto& tpcGlobal = comsmicInfo[GTrackID::TPC]; + auto& tofGlobal = comsmicInfo[GTrackID::TOF]; + if (tpcGlobal.isIndexSet() && tofGlobal.isIndexSet()) { + const auto itrTPC = tpcGlobal.getIndex(); + const auto itrTOF = tofGlobal.getIndex(); + const auto& tofCl = tof[itrTOF]; + const auto tofTime = tofCl.getTime() * 1e-6 * invBinWidth; // ps -> us -> time bins + const auto tofTimeRaw = tofCl.getTimeRaw() * 1e-6 * invBinWidth; // ps -> us -> time bins + const auto& trackTPC = mTPCTracksArray[itrTPC]; + // LOGP(info, "Cosmic time: {}, TOF time: {}, TOF time raw: {}, TPC time: {}", trackTime, tofTime, tofTimeRaw, trackTPC.getTime0()); + processTPCTrack(trackTPC, mUseMC ? mTPCTrkLabels[itrTPC] : o2::MCCompLabel{}, mDBGOutCosmics.get(), nullptr, nullptr, false, tofTime); + } + } + } +} + +DataProcessorSpec getTPCRefitterSpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, bool requestCosmics) { std::vector outputs; Options opts{ {"target-x", VariantType::Float, 83.f, {"Try to propagate to this radius"}}, {"dump-clusters", VariantType::Bool, false, {"dump all clusters"}}, - {"write-track-clusters", VariantType::Bool, false, {"write clusters associated to the track, uncorrected and corrected positions"}}, + {"write-track-clusters", VariantType::Int, 3, {"Bitmask write clusters associated to the track, full native cluster (0x1), corrected (0x2) and uncorrected (0x4) positions, (0x8) occupancy info"}}, {"tf-start", VariantType::Int, 0, {"1st TF to process"}}, {"tf-end", VariantType::Int, 999999999, {"last TF to process"}}, {"use-gpu-fitter", VariantType::Bool, false, {"use GPU track model for refit instead of TrackParCov"}}, + {"do-refit", VariantType::Bool, false, {"do refitting of TPC track"}}, {"use-r-as-x", VariantType::Bool, false, {"Use radius instead of target sector X"}}, {"enable-dcas", VariantType::Bool, false, {"Propagate to DCA and add it to the tree"}}, {"dcaMinPt", VariantType::Float, 1.f, {"Min pT of tracks propagated to DCA"}}, {"dcaMinNCl", VariantType::Int, 80, {"Min number of clusters for tracks propagated to DCA"}}, + {"sqrts", VariantType::Float, 13600.f, {"Centre of mass energy used for downsampling"}}, + {"do-sampling", VariantType::Bool, false, {"Perform sampling, min. bias and on Tsallis function, using 'sampling-factor'"}}, + {"sampling-factor", VariantType::Float, 0.1f, {"Sampling factor in case sample-unbinned-tsallis is used"}}, + {"study-type", VariantType::Int, 1, {"Bitmask of study type: 0x1 = TPC only, 0x2 = TPC + ITS, 0x4 = Cosmics"}}, + {"writer-type", VariantType::Int, 1, {"Bitmask of writer type: 0x1 = per track streamer, 0x2 = per TF vectors"}}, + {"occupancy-bins-per-drift", VariantType::UInt32, 31u, {"number of bin for occupancy histogram per drift time (500tb)"}}, }; auto dataRequest = std::make_shared(); dataRequest->requestTracks(srcTracks, useMC); dataRequest->requestClusters(srcClusters, useMC); + if (requestCosmics) { + dataRequest->requestCoscmicTracks(useMC); + } auto ggRequest = std::make_shared(false, // orbitResetTime true, // GRPECS=true false, // GRPLHCIF diff --git a/Detectors/TPC/workflow/src/tpc-miptrack-filter.cxx b/Detectors/TPC/workflow/src/tpc-miptrack-filter.cxx index d4c311edac19c..112e8ff2cd3a4 100644 --- a/Detectors/TPC/workflow/src/tpc-miptrack-filter.cxx +++ b/Detectors/TPC/workflow/src/tpc-miptrack-filter.cxx @@ -49,10 +49,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) auto logger = BranchDefinition::Spectator([](TrackOutputType const& tracks) { LOG(info) << "writing " << tracks.size() << " track(s)"; }); - auto tracksdef = BranchDefinition{InputSpec{"inputTracks", "TPC", "MIPS", 0}, // - "TPCTracks", "track-branch-name", // - 1, // - logger}; // + auto tracksdef = BranchDefinition{InputSpec{"inputTracks", "TPC", "MIPS", 0, Lifetime::Sporadic}, // + "TPCTracks", "track-branch-name", // + 1, // + logger}; // workflow.push_back(MakeRootTreeWriterSpec(processName, defaultFileName, defaultTreeName, std::move(tracksdef))()); diff --git a/Detectors/TPC/workflow/src/tpc-refitter-workflow.cxx b/Detectors/TPC/workflow/src/tpc-refitter-workflow.cxx index 9a0fdc0e26b53..264e7d8a98c60 100644 --- a/Detectors/TPC/workflow/src/tpc-refitter-workflow.cxx +++ b/Detectors/TPC/workflow/src/tpc-refitter-workflow.cxx @@ -39,6 +39,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ {"enable-mc", o2::framework::VariantType::Bool, false, {"enable MC propagation"}}, + {"enable-cosmics", o2::framework::VariantType::Bool, false, {"enable reading cosmics"}}, {"track-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of track sources to use"}}, {"cluster-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of cluster sources to use"}}, {"disable-root-input", VariantType::Bool, false, {"disable root-files input reader"}}, @@ -58,19 +59,25 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { WorkflowSpec specs; - GID::mask_t allowedSourcesTrc = GID::getSourcesMask("TPC"); - GID::mask_t allowedSourcesClus = GID::getSourcesMask("TPC"); - // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); auto useMC = configcontext.options().get("enable-mc"); auto sclOpt = o2::tpc::CorrectionMapsLoader::parseGlobalOptions(configcontext.options()); + const auto enableCosmics = configcontext.options().get("enable-cosmics"); + + GID::mask_t allowedSourcesTrc = GID::getSourcesMask("ITS,TPC,ITS-TPC,TPC-TOF"); + GID::mask_t allowedSourcesClus = GID::getSourcesMask("TPC,TOF"); + if (enableCosmics) { + allowedSourcesTrc = allowedSourcesTrc | GID::getSourcesMask("ITS-TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD-TOF"); + } + GID::mask_t srcTrc = allowedSourcesTrc & GID::getSourcesMask(configcontext.options().get("track-sources")); GID::mask_t srcCls = allowedSourcesClus & GID::getSourcesMask(configcontext.options().get("cluster-sources")); if (sclOpt.requestCTPLumi) { srcTrc = srcTrc | GID::getSourcesMask("CTP"); srcCls = srcCls | GID::getSourcesMask("CTP"); } + if (sclOpt.lumiType == 2) { const auto enableMShape = configcontext.options().get("enable-M-shape-correction"); const auto enableIDCs = !configcontext.options().get("disable-IDC-scalers"); @@ -79,7 +86,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, useMC); o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, useMC); // P-vertex is always needed - specs.emplace_back(o2::trackstudy::getTPCRefitterSpec(srcTrc, srcCls, useMC, sclOpt)); + if (enableCosmics) { + o2::globaltracking::InputHelper::addInputSpecsCosmics(configcontext, specs, useMC); + } + specs.emplace_back(o2::trackstudy::getTPCRefitterSpec(srcTrc, srcCls, useMC, sclOpt, enableCosmics)); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs);