diff --git a/Detectors/TPC/base/include/TPCBase/CDBInterface.h b/Detectors/TPC/base/include/TPCBase/CDBInterface.h index d603e26d9f647..8eccf540f3d22 100644 --- a/Detectors/TPC/base/include/TPCBase/CDBInterface.h +++ b/Detectors/TPC/base/include/TPCBase/CDBInterface.h @@ -88,6 +88,7 @@ enum class CDBType { CalCorrDerivMap, ///< Cluster correction map (derivative map) /// CalTimeSeries, ///< integrated DCAs for longer time interval + CalScaler, ///< Scaler from IDCs or combined estimator }; /// Upload intervention type @@ -149,6 +150,7 @@ const std::unordered_map CDBTypeMap{ {CDBType::CalCorrDerivMap, "TPC/Calib/CorrectionMapDerivativeV2"}, // time series {CDBType::CalTimeSeries, "TPC/Calib/TimeSeries"}, + {CDBType::CalScaler, "TPC/Calib/Scaler"}, }; /// Poor enum reflection ... diff --git a/Detectors/TPC/calibration/CMakeLists.txt b/Detectors/TPC/calibration/CMakeLists.txt index e8387b12684b9..5b5d2f03ade0b 100644 --- a/Detectors/TPC/calibration/CMakeLists.txt +++ b/Detectors/TPC/calibration/CMakeLists.txt @@ -52,6 +52,7 @@ o2_add_library(TPCCalibration src/SACCCDBHelper.cxx src/TPCFastSpaceChargeCorrectionHelper.cxx src/CalculatedEdx.cxx + src/TPCScaler.cxx PUBLIC_LINK_LIBRARIES O2::DataFormatsTPC O2::TPCBase O2::TPCReconstruction ROOT::Minuit Microsoft.GSL::GSL @@ -103,7 +104,8 @@ o2_target_root_dictionary(TPCCalibration include/TPCCalibration/VDriftHelper.h include/TPCCalibration/SACCCDBHelper.h include/TPCCalibration/TPCFastSpaceChargeCorrectionHelper.h - include/TPCCalibration/CalculatedEdx.h) + include/TPCCalibration/CalculatedEdx.h + include/TPCCalibration/TPCScaler.h) o2_add_test_root_macro(macro/comparePedestalsAndNoise.C PUBLIC_LINK_LIBRARIES O2::TPCBase diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h b/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h index 3f832e35557fb..56d277e50d3db 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h @@ -50,7 +50,7 @@ class CorrectionMapsLoader : public o2::gpu::CorrectionMapsHelper void init(o2::framework::InitContext& ic); void copySettings(const CorrectionMapsLoader& src); - static void requestCCDBInputs(std::vector& inputs, std::vector& options, bool requestCTPLumi = false, int lumiScaleMode = 0); + static void requestCCDBInputs(std::vector& inputs, std::vector& options, int lumiScaleType = 0, int lumiScaleMode = 0); static void addOptions(std::vector& options); protected: diff --git a/Detectors/TPC/calibration/include/TPCCalibration/TPCScaler.h b/Detectors/TPC/calibration/include/TPCCalibration/TPCScaler.h new file mode 100644 index 0000000000000..131fb626c7654 --- /dev/null +++ b/Detectors/TPC/calibration/include/TPCCalibration/TPCScaler.h @@ -0,0 +1,113 @@ +// 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 TPCScaler.h +/// \author Matthias Kleiner + +#ifndef ALICEO2_TPC_TPCSCALER +#define ALICEO2_TPC_TPCSCALER + +#include "DataFormatsTPC/Defs.h" +#include + +class TTree; + +namespace o2::tpc +{ + +/* +Class for storing the scalers which are used to calculate an estimate for the mean space-charge density for the last ion drift time +*/ + +class TPCScaler +{ + public: + /// default constructor + TPCScaler() = default; + + /// default move assignment + TPCScaler& operator=(TPCScaler&& other) = default; + + /// \return returns number of stored TPC scaler values + int getNValues(o2::tpc::Side side) const { return (side == o2::tpc::Side::A ? mScalerA.size() : mScalerC.size()); } + + /// set the parameters for the coefficients of the polynomial + /// \param params parameter for the coefficients + void setScaler(const std::vector& values, const o2::tpc::Side side) { (side == o2::tpc::Side::A ? (mScalerA = values) : (mScalerC = values)); } + + /// \return returns ion drift time in ms + void setIonDriftTimeMS(float ionDriftTimeMS) { mIonDriftTimeMS = ionDriftTimeMS; } + + /// \return returns run number for which this object is valid + void setRun(int run) { mRun = run; } + + /// \param firstTFOrbit first TF orbit of first data + void setFirstTFOrbit(unsigned int firstTFOrbit) { mFirstTFOrbit = firstTFOrbit; } + + /// \param timeStampMS first time in ms + void setStartTimeStampMS(double timeStampMS) { mTimeStampMS = timeStampMS; } + + /// \param integrationTimeMS integration time for each scaler value + void setIntegrationTimeMS(float integrationTimeMS) { mIntegrationTimeMS = integrationTimeMS; } + + /// dump this object to a file + /// \param file output file + void dumpToFile(const char* file, const char* name); + + /// load parameters from input file (which were written using the writeToFile method) + /// \param inpf input file + void loadFromFile(const char* inpf, const char* name); + + /// set this object from input tree + void setFromTree(TTree& tpcScalerTree); + + /// \return returns stored scalers for given side and data index + float getScalers(unsigned int idx, o2::tpc::Side side) const { return (side == o2::tpc::Side::A) ? mScalerA[idx] : mScalerC[idx]; } + + /// \return returns stored scalers for given side + const auto& getScalers(o2::tpc::Side side) const { return (side == o2::tpc::Side::A) ? mScalerA : mScalerC; } + + /// \return returns ion drift time in ms + float getIonDriftTimeMS() const { return mIonDriftTimeMS; } + + /// \return returns run number for which this object is valid + int getRun() const { return mRun; } + + /// \return returns first TF orbit of first data + unsigned int getFirstTFOrbit() const { return mFirstTFOrbit; } + + /// \return return first time in ms + double getStartTimeStampMS() const { return mTimeStampMS; } + + /// \return returns integration time for each scaler value + float getIntegrationTimeMS() const { return mIntegrationTimeMS; } + + /// \return returns numbers of scalers for one ion drift time + int getNValuesIonDriftTime() const { return mIonDriftTimeMS / mIntegrationTimeMS + 0.5; } + + /// \return returns mean scaler value for last ion drift time + /// \param timestamp timestamp for which the last values are used to calculate the mean + float getMeanScaler(double timestamp, o2::tpc::Side side) const; + + private: + float mIonDriftTimeMS{200}; ///< ion drift time in ms + int mRun{}; ///< run for which this object is valid + unsigned int mFirstTFOrbit{}; ///< first TF orbit of the stored scalers + double mTimeStampMS{}; ///< time stamp of the first stored values + float mIntegrationTimeMS{1.}; ///< integration time for each stored value in ms + std::vector mScalerA{}; ///< TPC scaler for A-side + std::vector mScalerC{}; ///< TPC scaler for C-side + + ClassDefNV(TPCScaler, 1); +}; + +} // namespace o2::tpc +#endif diff --git a/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx b/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx index 92432162872a9..a86246e9c015f 100644 --- a/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx +++ b/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx @@ -46,7 +46,7 @@ void CorrectionMapsLoader::extractCCDBInputs(ProcessingContext& pc) int dumRep = 0; o2::ctp::LumiInfo lumiObj; static o2::ctp::LumiInfo lumiPrev; - if (getUseCTPLumi() && mInstLumiOverride <= 0.) { + if (getLumiScaleType() == 1 && mInstLumiOverride <= 0.) { if (pc.inputs().get>("CTPLumi").size() == sizeof(o2::ctp::LumiInfo)) { lumiPrev = lumiObj = pc.inputs().get("CTPLumi"); } else { @@ -56,13 +56,16 @@ void CorrectionMapsLoader::extractCCDBInputs(ProcessingContext& pc) lumiObj = lumiPrev; } setInstLumi(mInstLumiFactor * (mCTPLumiSource == 0 ? lumiObj.getLumi() : lumiObj.getLumiAlt())); + } else if (getLumiScaleType() == 2 && mInstLumiOverride <= 0.) { + float tpcScaler = pc.inputs().get("tpcscaler"); + setInstLumi(mInstLumiFactor * tpcScaler); } } //________________________________________________________ -void CorrectionMapsLoader::requestCCDBInputs(std::vector& inputs, std::vector& options, bool requestCTPLumi, int lumiScaleMode) +void CorrectionMapsLoader::requestCCDBInputs(std::vector& inputs, std::vector& options, int lumiScaleType, int lumiScaleMode) { - addInput(inputs, {"tpcCorrMap", "TPC", "CorrMap", 0, Lifetime::Condition, ccdbParamSpec(CDBTypeMap.at(CDBType::CalCorrMap), {}, 1)}); // time-dependent + addInput(inputs, {"tpcCorrMap", "TPC", "CorrMap", 0, Lifetime::Condition, ccdbParamSpec(CDBTypeMap.at(CDBType::CalCorrMap), {}, 1)}); // time-dependent if (lumiScaleMode == 0) { addInput(inputs, {"tpcCorrMapRef", "TPC", "CorrMapRef", 0, Lifetime::Condition, ccdbParamSpec(CDBTypeMap.at(CDBType::CalCorrMapRef), {}, 0)}); // load once } else if (lumiScaleMode == 1) { @@ -71,8 +74,10 @@ void CorrectionMapsLoader::requestCCDBInputs(std::vector& inputs, std LOG(fatal) << "Correction mode unknown! Choose either 0 (default) or 1 (derivative map) for flag corrmap-lumi-mode."; } - if (requestCTPLumi) { + if (lumiScaleType == 1) { addInput(inputs, {"CTPLumi", "CTP", "LUMI", 0, Lifetime::Timeframe}); + } else if (lumiScaleType == 2) { + addInput(inputs, {"tpcscaler", o2::header::gDataOriginTPC, "TPCSCALER", 0, Lifetime::Timeframe}); } addOptions(options); } @@ -131,8 +136,10 @@ void CorrectionMapsLoader::init(o2::framework::InitContext& ic) const auto& inputRouts = ic.services().get().inputs; for (const auto& route : inputRouts) { if (route.matcher == InputSpec{"CTPLumi", "CTP", "LUMI", 0, Lifetime::Timeframe}) { - setUseCTPLumi(true); + setLumiScaleType(1); break; + } else if (route.matcher == InputSpec{"tpcscaler", o2::header::gDataOriginTPC, "TPCSCALER", 0, Lifetime::Timeframe}) { + setLumiScaleType(2); } } mMeanLumiOverride = ic.options().get("corrmap-lumi-mean"); @@ -146,8 +153,14 @@ void CorrectionMapsLoader::init(o2::framework::InitContext& ic) if (mInstLumiOverride != 0.) { setInstLumi(mInstLumiOverride); } - LOGP(info, "CTP Lumi request for TPC corr.map scaling={}, override values: lumiMean={} lumiInst={} lumiScaleMode={}, LumiInst scale={}, CTP Lumi source={}", - getUseCTPLumi() ? "ON" : "OFF", mMeanLumiOverride, mInstLumiOverride, mLumiScaleMode, mInstLumiFactor, mCTPLumiSource); + const std::array lumiS{"OFF", "CTP", "TPC scaler"}; + int scaleType = getLumiScaleType(); + if (scaleType >= lumiS.size()) { + LOGP(fatal, "Wrong lumi-scale-type provided!"); + } + + LOGP(info, "Scaling for TPC corr.map scaling={}, override values: lumiMean={} lumiInst={} lumiScaleMode={}, LumiInst scale={}, CTP Lumi source={}", + lumiS[scaleType], mMeanLumiOverride, mInstLumiOverride, mLumiScaleMode, mInstLumiFactor, mCTPLumiSource); } //________________________________________________________ @@ -155,7 +168,7 @@ void CorrectionMapsLoader::copySettings(const CorrectionMapsLoader& src) { setInstLumi(src.getInstLumi(), false); setMeanLumi(src.getMeanLumi(), false); - setUseCTPLumi(src.getUseCTPLumi()); + setLumiScaleType(src.getLumiScaleType()); setMeanLumiOverride(src.getMeanLumiOverride()); setInstLumiOverride(src.getInstLumiOverride()); setLumiScaleMode(src.getLumiScaleMode()); diff --git a/Detectors/TPC/calibration/src/TPCCalibrationLinkDef.h b/Detectors/TPC/calibration/src/TPCCalibrationLinkDef.h index a0c96b48b1d44..a59772256a309 100644 --- a/Detectors/TPC/calibration/src/TPCCalibrationLinkDef.h +++ b/Detectors/TPC/calibration/src/TPCCalibrationLinkDef.h @@ -110,4 +110,5 @@ #pragma link C++ class o2::tpc::TPCFastSpaceChargeCorrectionHelper + ; #pragma link C++ class o2::tpc::CalculatedEdx + ; +#pragma link C++ class o2::tpc::TPCScaler + ; #endif diff --git a/Detectors/TPC/calibration/src/TPCScaler.cxx b/Detectors/TPC/calibration/src/TPCScaler.cxx new file mode 100644 index 0000000000000..cb145dd112b07 --- /dev/null +++ b/Detectors/TPC/calibration/src/TPCScaler.cxx @@ -0,0 +1,74 @@ +// 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 TPCScaler.cxx +/// \brief Definition of TPCScaler class +/// +/// \author Matthias Kleiner + +#include "TPCCalibration/TPCScaler.h" +#include +#include +#include "Framework/Logger.h" + +using namespace o2::tpc; + +void TPCScaler::dumpToFile(const char* file, const char* name) +{ + TFile out(file, "RECREATE"); + TTree tree("TPCScaler", "TPCScaler"); + tree.Branch("TPCScaler", this); + tree.Fill(); + out.WriteObject(&tree, name); +} + +void TPCScaler::loadFromFile(const char* inpf, const char* name) +{ + TFile out(inpf, "READ"); + TTree* tree = (TTree*)out.Get(name); + setFromTree(*tree); +} + +void TPCScaler::setFromTree(TTree& tpcScalerTree) +{ + TPCScaler* scalerTmp = this; + tpcScalerTree.SetBranchAddress("TPCScaler", &scalerTmp); + const int entries = tpcScalerTree.GetEntries(); + if (entries > 0) { + tpcScalerTree.GetEntry(0); + } else { + LOGP(error, "TPCScaler not found in input file"); + } + tpcScalerTree.SetBranchAddress("TPCScaler", nullptr); +} + +float TPCScaler::getMeanScaler(double timestamp, o2::tpc::Side side) const +{ + // index to data buffer + const int idxData = (timestamp - mTimeStampMS) / mIntegrationTimeMS + 0.5; + const int nVals = getNValuesIonDriftTime(); + const int nValues = getNValues(side); + if ((nVals == 0) || (nVals > nValues)) { + return -1; + LOGP(error, "Empty data provided {}", nValues); + } + + // clamp indices to min and max + const int lastIdx = std::clamp(idxData, nVals, nValues); + const int firstIdx = (lastIdx == nValues) ? (nValues - nVals) : std::clamp(idxData - nVals, 0, nValues); + + // sump up values from last ion drift time + float sum = 0; + for (int i = firstIdx; i < lastIdx; ++i) { + sum += getScalers(i, side); + } + return (sum / nVals); +} diff --git a/Detectors/TPC/workflow/CMakeLists.txt b/Detectors/TPC/workflow/CMakeLists.txt index a12ccc83b1cc2..0541d6dc1e2ba 100644 --- a/Detectors/TPC/workflow/CMakeLists.txt +++ b/Detectors/TPC/workflow/CMakeLists.txt @@ -45,6 +45,7 @@ o2_add_library(TPCWorkflow src/TPCTimeSeriesWriterSpec.cxx src/TPCTimeSeriesReaderSpec.cxx src/TPCMergeTimeSeriesSpec.cxx + src/TPCScalerSpec.cxx TARGETVARNAME targetName PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsTPC O2::DPLUtils O2::TPCReconstruction @@ -246,6 +247,11 @@ o2_add_executable(merge-time-series-workflow COMPONENT_NAME tpc PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) +o2_add_executable(scaler-workflow + COMPONENT_NAME tpc + SOURCES src/tpc-scaler.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + o2_add_test(workflow COMPONENT_NAME tpc LABELS tpc workflow diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h b/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h index ad8560d48fe87..a7f0f66a11fd9 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h @@ -84,7 +84,7 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, bool askDISTSTF = true, bool selIR = false, bool filteredInp = false, - bool requireCTPLumi = false, + int lumiScaleType = 0, int deadMapSources = -1); void cleanupCallback(); diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h index f87b5129b3d33..9d6004b113823 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h @@ -240,7 +240,7 @@ class TPCCalibPadGainTracksDevice : public o2::framework::Task } }; -DataProcessorSpec getTPCCalibPadGainTracksSpec(const uint32_t publishAfterTFs, const bool debug, const bool useLastExtractedMapAsReference, const std::string polynomialsFile, bool disablePolynomialsCCDB, bool requestCTPLumi) +DataProcessorSpec getTPCCalibPadGainTracksSpec(const uint32_t publishAfterTFs, const bool debug, const bool useLastExtractedMapAsReference, const std::string polynomialsFile, bool disablePolynomialsCCDB, int lumiType) { std::vector inputs; inputs.emplace_back("trackTPC", gDataOriginTPC, "TRACKS", 0, Lifetime::Timeframe); @@ -282,7 +282,7 @@ DataProcessorSpec getTPCCalibPadGainTracksSpec(const uint32_t publishAfterTFs, c {"useEveryNthTF", VariantType::Int, 10, {"Using only a fraction of the data: 1: Use every TF, 10: Use only every tenth TF."}}, {"maxTracksPerTF", VariantType::Int, 10000, {"Maximum number of processed tracks per TF (-1 for processing all tracks)"}}, }; - o2::tpc::CorrectionMapsLoader::requestCCDBInputs(inputs, opts, requestCTPLumi); + o2::tpc::CorrectionMapsLoader::requestCCDBInputs(inputs, opts, lumiType); auto ccdbRequest = std::make_shared(false, // orbitResetTime false, // GRPECS=true diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCScalerSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCScalerSpec.h new file mode 100644 index 0000000000000..2bd3ca89bfb6a --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCScalerSpec.h @@ -0,0 +1,27 @@ +// 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. + +#ifndef O2_TPC_TPCSCALER_SPEC +#define O2_TPC_TPCSCALER_SPEC + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace tpc +{ + +o2::framework::DataProcessorSpec getTPCScalerSpec(); + +} // end namespace tpc +} // end namespace o2 + +#endif diff --git a/Detectors/TPC/workflow/src/RecoWorkflow.cxx b/Detectors/TPC/workflow/src/RecoWorkflow.cxx index 0b6267643f232..f5c1afd42acfc 100644 --- a/Detectors/TPC/workflow/src/RecoWorkflow.cxx +++ b/Detectors/TPC/workflow/src/RecoWorkflow.cxx @@ -98,7 +98,7 @@ const std::unordered_map OutputMap{ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vector const& tpcSectors, unsigned long tpcSectorMask, std::vector const& laneConfiguration, bool propagateMC, unsigned nLanes, std::string const& cfgInput, std::string const& cfgOutput, bool disableRootInput, - int caClusterer, int zsOnTheFly, bool askDISTSTF, bool selIR, bool filteredInp, bool requireCTPLumi, int deadMapSources) + int caClusterer, int zsOnTheFly, bool askDISTSTF, bool selIR, bool filteredInp, int lumiScaleType, int deadMapSources) { InputType inputType; try { @@ -440,7 +440,7 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto if (runGPUReco) { o2::gpu::GPURecoWorkflowSpec::Config cfg; cfg.runTPCTracking = true; - cfg.requireCTPLumi = requireCTPLumi; + cfg.lumiScaleType = lumiScaleType; cfg.decompressTPC = decompressTPC; cfg.decompressTPCFromROOT = decompressTPC && inputType == InputType::CompClusters; cfg.caClusterer = caClusterer; diff --git a/Detectors/TPC/workflow/src/TPCScalerSpec.cxx b/Detectors/TPC/workflow/src/TPCScalerSpec.cxx new file mode 100644 index 0000000000000..35c8c34c36604 --- /dev/null +++ b/Detectors/TPC/workflow/src/TPCScalerSpec.cxx @@ -0,0 +1,111 @@ +// 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 TPCScalerSpec.cxx +/// \brief device for providing tpc scaler per TF +/// \author Matthias Kleiner +/// \date Nov 4, 2023 + +#include "Framework/Task.h" +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/CCDBParamSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "TPCBase/CDBInterface.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "TPCCalibration/TPCScaler.h" +#include "TTree.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace tpc +{ + +class TPCScalerSpec : public Task +{ + public: + TPCScalerSpec(std::shared_ptr req) : mCCDBRequest(req){}; + + void init(framework::InitContext& ic) final + { + o2::base::GRPGeomHelper::instance().setRequest(mCCDBRequest); + mIonDriftTimeMS = ic.options().get("ion-drift-time"); + } + + void run(ProcessingContext& pc) final + { + o2::base::GRPGeomHelper::instance().checkUpdates(pc); + if (pc.inputs().isValid("tpcscaler")) { + pc.inputs().get("tpcscaler"); + } + + if (pc.services().get().runNumber != mTPCScaler.getRun()) { + LOGP(error, "Run number {} of processed data and run number {} of loaded TPC scaler doesnt match!", pc.services().get().runNumber, mTPCScaler.getRun()); + } + + const auto orbitResetTimeMS = o2::base::GRPGeomHelper::instance().getOrbitResetTimeMS(); + const auto firstTFOrbit = pc.services().get().firstTForbit; + const double timestamp = orbitResetTimeMS + firstTFOrbit * o2::constants::lhc::LHCOrbitMUS * 0.001; + float scalerA = mTPCScaler.getMeanScaler(timestamp, o2::tpc::Side::A); + float scalerC = mTPCScaler.getMeanScaler(timestamp, o2::tpc::Side::C); + float meanScaler = (scalerA + scalerC) / 2; + LOGP(info, "Publishing TPC scaler: {}", meanScaler); + pc.outputs().snapshot(Output{header::gDataOriginTPC, "TPCSCALER"}, meanScaler); + } + + void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) final + { + o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj); + if (matcher == ConcreteDataMatcher(o2::header::gDataOriginTPC, "TPCSCALERCCDB", 0)) { + LOGP(info, "Updating TPC scaler"); + mTPCScaler.setFromTree(*((TTree*)obj)); + if (mIonDriftTimeMS > 0) { + LOGP(info, "Setting ion drift time to: {}", mIonDriftTimeMS); + mTPCScaler.setIonDriftTimeMS(mIonDriftTimeMS); + } + } + } + + private: + std::shared_ptr mCCDBRequest; ///< info for CCDB request + float mIonDriftTimeMS{-1}; ///< ion drift time + TPCScaler mTPCScaler; ///< tpc scaler +}; + +o2::framework::DataProcessorSpec getTPCScalerSpec() +{ + std::vector inputs; + inputs.emplace_back("tpcscaler", o2::header::gDataOriginTPC, "TPCSCALERCCDB", 0, Lifetime::Condition, ccdbParamSpec(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::CalScaler))); + + auto ccdbRequest = std::make_shared(true, // orbitResetTime + false, // GRPECS=true for nHBF per TF + false, // GRPLHCIF + false, // GRPMagField + false, // askMatLUT + o2::base::GRPGeomRequest::None, // geometry + inputs); + + std::vector outputs; + outputs.emplace_back(o2::header::gDataOriginTPC, "TPCSCALER", 0, Lifetime::Timeframe); + + return DataProcessorSpec{ + "tpc-scaler", + inputs, + outputs, + AlgorithmSpec{adaptFromTask(ccdbRequest)}, + Options{ + {"ion-drift-time", VariantType::Float, -1.f, {"Overwrite ion drift time if a value >0 is provided"}}}}; +} + +} // namespace tpc +} // namespace o2 diff --git a/Detectors/TPC/workflow/src/tpc-calib-gainmap-tracks.cxx b/Detectors/TPC/workflow/src/tpc-calib-gainmap-tracks.cxx index 069fc0be7b936..1dfdaf34276ca 100644 --- a/Detectors/TPC/workflow/src/tpc-calib-gainmap-tracks.cxx +++ b/Detectors/TPC/workflow/src/tpc-calib-gainmap-tracks.cxx @@ -41,7 +41,7 @@ void customize(std::vector& workflowOptions) {"useLastExtractedMapAsReference", VariantType::Bool, false, {"enabling iterative extraction of the gain map: Using the extracted gain map from the previous iteration to correct the cluster charge"}}, {"polynomialsFile", VariantType::String, "", {"file containing the polynomials for the track topology correction"}}, {"disablePolynomialsCCDB", VariantType::Bool, false, {"Do not load the polynomials from the CCDB"}}, - {"require-ctp-lumi", o2::framework::VariantType::Bool, false, {"require CTP lumi for TPC correction scaling"}}, + {"lumi-type", o2::framework::VariantType::Int, 0, {"1 = require CTP lumi for TPC correction scaling, 2 = require TPC scalers for TPC correction scaling"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; std::swap(workflowOptions, options); @@ -57,13 +57,13 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) o2::conf::ConfigurableParam::updateFromFile(config.options().get("configFile")); o2::conf::ConfigurableParam::updateFromString(config.options().get("configKeyValues")); o2::conf::ConfigurableParam::writeINI("o2tpcpadgaintrackscalibrator_configuration.ini"); - auto requireCTPLumi = config.options().get("require-ctp-lumi"); + auto lumiType = config.options().get("lumi-type"); const auto debug = config.options().get("debug"); const auto publishAfterTFs = (uint32_t)config.options().get("publish-after-tfs"); const bool useLastExtractedMapAsReference = config.options().get("useLastExtractedMapAsReference"); const std::string polynomialsFile = config.options().get("polynomialsFile"); const auto disablePolynomialsCCDB = config.options().get("disablePolynomialsCCDB"); - WorkflowSpec workflow{getTPCCalibPadGainTracksSpec(publishAfterTFs, debug, useLastExtractedMapAsReference, polynomialsFile, disablePolynomialsCCDB, requireCTPLumi)}; + WorkflowSpec workflow{getTPCCalibPadGainTracksSpec(publishAfterTFs, debug, useLastExtractedMapAsReference, polynomialsFile, disablePolynomialsCCDB, lumiType)}; return workflow; } diff --git a/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx b/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx index bc1d7b22fbad4..3aca0353289a9 100644 --- a/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx +++ b/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx @@ -68,7 +68,7 @@ void customize(std::vector& workflowOptions) {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings (e.g.: 'TPCHwClusterer.peakChargeThreshold=4;...')"}}, {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}, {"filtered-input", VariantType::Bool, false, {"Filtered tracks, clusters input, prefix dataDescriptors with F"}}, - {"require-ctp-lumi", o2::framework::VariantType::Bool, false, {"require CTP lumi for TPC correction scaling"}}, + {"lumi-type", o2::framework::VariantType::Int, 0, {"1 = require CTP lumi for TPC correction scaling, 2 = require TPC scalers for TPC correction scaling"}}, {"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}, {"tpc-deadMap-sources", VariantType::Int, -1, {"Sources to consider for TPC dead channel map creation; -1=all, 0=deactivated"}}, }; @@ -140,7 +140,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) std::vector laneConfiguration = tpcSectors; // Currently just a copy of the tpcSectors, why? auto nLanes = cfgc.options().get("tpc-lanes"); auto inputType = cfgc.options().get("input-type"); - auto requireCTPLumi = cfgc.options().get("require-ctp-lumi"); + auto lumiType = cfgc.options().get("lumi-type"); // depending on whether to dispatch early (prompt) and on the input type, we // set the matcher. Note that this has to be in accordance with the OutputSpecs // configured for the PublisherSpec @@ -181,7 +181,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) !cfgc.options().get("ignore-dist-stf"), // cfgc.options().get("select-ir-frames"), cfgc.options().get("filtered-input"), - requireCTPLumi, + lumiType, cfgc.options().get("tpc-deadMap-sources")); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit diff --git a/Detectors/TPC/workflow/src/tpc-scaler.cxx b/Detectors/TPC/workflow/src/tpc-scaler.cxx new file mode 100644 index 0000000000000..e9bc8c4a1f035 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-scaler.cxx @@ -0,0 +1,36 @@ +// 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 tpc-scaler.cxx +/// \author Matthias Kleiner, mkleiner@ikf.uni-frankfurt.de + +#include "TPCWorkflow/TPCScalerSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" + +using namespace o2::framework; + +void customize(std::vector& workflowOptions) +{ + // option allowing to set parameters + std::vector options{ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + WorkflowSpec workflow; + o2::conf::ConfigurableParam::updateFromString(config.options().get("configKeyValues")); + workflow.emplace_back(o2::tpc::getTPCScalerSpec()); + return workflow; +} diff --git a/GPU/TPCFastTransformation/CorrectionMapsHelper.cxx b/GPU/TPCFastTransformation/CorrectionMapsHelper.cxx index 0d8dd922dad81..91439c587f63a 100644 --- a/GPU/TPCFastTransformation/CorrectionMapsHelper.cxx +++ b/GPU/TPCFastTransformation/CorrectionMapsHelper.cxx @@ -77,5 +77,5 @@ void CorrectionMapsHelper::setCorrMapRef(std::unique_ptr&& m) //________________________________________________________ void CorrectionMapsHelper::reportScaling() { - LOGP(info, "InstLumiOverride={}, UseCTPLumi={} -> instLumi={}, meanLumi={} -> LumiScale={}, lumiScaleMode={}", getInstLumiOverride(), getUseCTPLumi(), getInstLumi(), getMeanLumi(), getLumiScale(), getLumiScaleMode()); + LOGP(info, "InstLumiOverride={}, LumiScaleType={} -> instLumi={}, meanLumi={} -> LumiScale={}, lumiScaleMode={}", getInstLumiOverride(), getLumiScaleType(), getInstLumi(), getMeanLumi(), getLumiScale(), getLumiScaleMode()); } diff --git a/GPU/TPCFastTransformation/CorrectionMapsHelper.h b/GPU/TPCFastTransformation/CorrectionMapsHelper.h index 5d3bedd83783c..88e00eec419ce 100644 --- a/GPU/TPCFastTransformation/CorrectionMapsHelper.h +++ b/GPU/TPCFastTransformation/CorrectionMapsHelper.h @@ -123,8 +123,8 @@ class CorrectionMapsHelper void setOwner(bool v); void acknowledgeUpdate() { mUpdatedFlags = 0; } - void setUseCTPLumi(bool v) { mUseCTPLumi = v; } - bool getUseCTPLumi() const { return mUseCTPLumi; } + void setLumiScaleType(int v) { mLumiScaleType = v; } + int getLumiScaleType() const { return mLumiScaleType; } void setMeanLumiOverride(float f) { mMeanLumiOverride = f; } float getMeanLumiOverride() const { return mMeanLumiOverride; } @@ -138,8 +138,8 @@ class CorrectionMapsHelper enum UpdateFlags { MapBit = 0x1, MapRefBit = 0x2, LumiBit = 0x4 }; - bool mOwner = false; // is content of pointers owned by the helper - bool mUseCTPLumi = false; // require CTP Lumi for mInstLumi + bool mOwner = false; // is content of pointers owned by the helper + int mLumiScaleType = 0; // require CTP Lumi for mInstLumi int mUpdatedFlags = 0; float mInstLumi = 0.; // instanteneous luminosity (a.u) float mMeanLumi = 0.; // mean luminosity of the map (a.u) @@ -150,7 +150,7 @@ class CorrectionMapsHelper GPUCA_NAMESPACE::gpu::TPCFastTransform* mCorrMap{nullptr}; // current transform GPUCA_NAMESPACE::gpu::TPCFastTransform* mCorrMapRef{nullptr}; // reference transform #ifndef GPUCA_ALIROOT_LIB - ClassDefNV(CorrectionMapsHelper, 2); + ClassDefNV(CorrectionMapsHelper, 3); #endif }; diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index 600f27ac092b7..351ae9d2ab967 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -123,7 +123,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task bool runTPCTracking = false; bool runTRDTracking = false; bool readTRDtracklets = false; - bool requireCTPLumi = false; + int lumiScaleType = 0; // 0=off, 1=CTP, 2=TPC scalers bool outputErrorQA = false; bool runITSTracking = false; bool itsOverrBeamEst = false; diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index bcb49d08baa8c..7132d7281a22d 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -1088,7 +1088,7 @@ Inputs GPURecoWorkflowSpec::inputs() inputs.emplace_back("tpcthreshold", gDataOriginTPC, "PADTHRESHOLD", 0, Lifetime::Condition, ccdbParamSpec("TPC/Config/FEEPad")); o2::tpc::VDriftHelper::requestCCDBInputs(inputs); Options optsDummy; - mCalibObjects.mFastTransformHelper->requestCCDBInputs(inputs, optsDummy, mSpecConfig.requireCTPLumi, mSpecConfig.lumiScaleMode); // option filled here is lost + mCalibObjects.mFastTransformHelper->requestCCDBInputs(inputs, optsDummy, mSpecConfig.lumiScaleType, mSpecConfig.lumiScaleMode); // option filled here is lost } if (mSpecConfig.decompressTPC) { inputs.emplace_back(InputSpec{"input", ConcreteDataTypeMatcher{gDataOriginTPC, mSpecConfig.decompressTPCFromROOT ? o2::header::DataDescription("COMPCLUSTERS") : o2::header::DataDescription("COMPCLUSTERSFLAT")}, Lifetime::Timeframe}); diff --git a/GPU/Workflow/src/gpu-reco-workflow.cxx b/GPU/Workflow/src/gpu-reco-workflow.cxx index d0bfc585168d1..8474d9eb8d30d 100644 --- a/GPU/Workflow/src/gpu-reco-workflow.cxx +++ b/GPU/Workflow/src/gpu-reco-workflow.cxx @@ -52,7 +52,7 @@ void customize(std::vector& workflowOptions) std::vector options{ {"input-type", VariantType::String, "digits", {"digitizer, digits, zsraw, zsonthefly, clustersnative, compressed-clusters-root, compressed-clusters-ctf, trd-tracklets"}}, {"output-type", VariantType::String, "tracks", {"clustersnative, tracks, compressed-clusters-ctf, qa, no-shared-cluster-map, send-clusters-per-sector, trd-tracks, error-qa, tpc-triggers"}}, - {"require-ctp-lumi", VariantType::Bool, false, {"require CTP lumi for TPC correction scaling"}}, + {"lumi-type", VariantType::Int, 0, {"1 = require CTP lumi for TPC correction scaling, 2 = require TPC scalers for TPC correction scaling"}}, {"disable-root-input", VariantType::Bool, true, {"disable root-files input reader"}}, {"disable-mc", VariantType::Bool, false, {"disable sending of MC information"}}, {"ignore-dist-stf", VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}, @@ -136,7 +136,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) std::iota(tpcSectors.begin(), tpcSectors.end(), 0); auto inputType = cfgc.options().get("input-type"); - auto requireCTPLumi = cfgc.options().get("require-ctp-lumi"); + auto lumiType = cfgc.options().get("lumi-type"); bool doMC = !cfgc.options().get("disable-mc"); o2::conf::ConfigurableParam::updateFromFile(cfgc.options().get("configFile")); @@ -157,7 +157,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) GPURecoWorkflowSpec::Config cfg; cfg.runTPCTracking = true; - cfg.requireCTPLumi = requireCTPLumi; + cfg.lumiScaleType = lumiType; cfg.decompressTPC = isEnabled(inputTypes, ioType::CompClustCTF); cfg.decompressTPCFromROOT = isEnabled(inputTypes, ioType::CompClustROOT); cfg.zsDecoder = isEnabled(inputTypes, ioType::ZSRaw); diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 826b78c70522b..1fc4c34361707 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -266,7 +266,23 @@ if [[ $IS_TRIGGERED_DATA == 1 ]]; then fi GPU_CONFIG_SELF="--severity $SEVERITY_TPC" -ASK_CTP_LUMI_GPU="--require-ctp-lumi" + +parse_TPC_CORR_SCALING() +{ +ASK_CTP_LUMI_GPU= +local restOpt= +while [[ $# -gt 0 ]]; do + case "$1" in + --lumi-type=*) ASK_CTP_LUMI_GPU=" --lumi-type ${1#*=}"; shift 1;; + --lumi-type) ASK_CTP_LUMI_GPU=" --lumi-type ${2}"; shift 2;; + *) restOpt+=" $1"; shift 1;; + esac +done +TPC_CORR_SCALING=$restOpt +} + +parse_TPC_CORR_SCALING $TPC_CORR_SCALING + : ${TPC_CORR_SCALING_GPU:=""} if [[ "$TPC_CORR_SCALING" == *"$ASK_CTP_LUMI_GPU"* ]]; then TPC_CORR_SCALING_GPU=${TPC_CORR_SCALING//$ASK_CTP_LUMI_GPU/}