diff --git a/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt b/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt index df42af503db46..4ee9f2f314a08 100644 --- a/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt +++ b/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt @@ -25,8 +25,9 @@ o2_add_library(GlobalTrackingStudy src/TrackMCStudyConfig.cxx src/TrackMCStudyTypes.cxx src/TPCClusSelector.cxx - src/CheckResid.cxx + src/CheckResidSpec.cxx src/CheckResidConfig.cxx + src/HistoManager.cxx PUBLIC_LINK_LIBRARIES O2::GlobalTracking O2::GlobalTrackingWorkflowReaders O2::GlobalTrackingWorkflowHelpers @@ -42,6 +43,7 @@ o2_target_root_dictionary(GlobalTrackingStudy include/GlobalTrackingStudy/TrackMCStudyTypes.h include/GlobalTrackingStudy/CheckResidTypes.h include/GlobalTrackingStudy/CheckResidConfig.h + include/GlobalTrackingStudy/HistoManager.h LINKDEF src/GlobalTrackingStudyLinkDef.h ) diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidConfig.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidConfig.h index 2a07eaf87930f..09ebba2d2e3f2 100644 --- a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidConfig.h +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidConfig.h @@ -21,7 +21,8 @@ struct CheckResidConfig : o2::conf::ConfigurableParamHelper { int minTPCCl = 60; int minITSCl = 7; float minPt = 0.4f; - float maxPt = 100.f; + float maxPt = 50.f; + float maxTgl = 2.f; float rCompIBOB = 12.f; bool pvcontribOnly = true; @@ -34,6 +35,27 @@ struct CheckResidConfig : o2::conf::ConfigurableParamHelper { float refitPVMV = false; float refitPVIniScale = 100.f; + std::string outname{"checkResid"}; + // histogram settings + int nBinsRes = 100; + int nBinsPhi = 30; + int nBinsZ = 20; + int nBinsPt = 15; + int nBinsTgl = 20; + int minHistoStat2Fit = 1000; + float maxPull = 4; + float zranges[8] = {10.f, 15.f, 15.f, 15.f, 40.f, 40.f, 74.f, 74.f}; + float maxDYZ[8] = {0.03, 0.015, 0.01, 0.01, 0.08, 0.08, 0.12, 0.1}; + float maxDPar[5] = {0.15, 0.15, 0.015, 0.015, 1.}; + // drawing settings + float resMMLrY[8] = {0.003, 0.003, 0.003, 0.003, 0.005, 0.005, 0.005, 0.005}; + float resMMLrZ[8] = {0.002, 0.0015, 0.0015, 0.0015, 0.005, 0.005, 0.005, 0.005}; + float resMMPar[5] = {0.03, 0.01, 0.005, 0.001, 0.5}; + // + // string with existing histomanagers files to draw (comma or semicolon separated) and optional legends + std::string ext_hm_list{}; + std::string ext_leg_list{}; + O2ParamDef(CheckResidConfig, "checkresid"); }; } // namespace o2::checkresid diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResid.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidSpec.h similarity index 91% rename from Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResid.h rename to Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidSpec.h index baba1a1d4d765..fceba6cb000fd 100644 --- a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResid.h +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidSpec.h @@ -19,7 +19,7 @@ namespace o2::checkresid { /// create a processor spec -o2::framework::DataProcessorSpec getCheckResidSpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC /*, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts*/); +o2::framework::DataProcessorSpec getCheckResidSpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool drawOnly); } // namespace o2::checkresid diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/HistoManager.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/HistoManager.h new file mode 100644 index 0000000000000..eb9cf6876333e --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/HistoManager.h @@ -0,0 +1,93 @@ +// Copyright 2019-2026 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_HISTOMANAGER_H_ +#define _O2_HISTOMANAGER_H_ + +#include +#include +#include "TObjArray.h" + +class TH1; +class TH2; +class TH1F; +class TH2F; +class TProfile; +class TGraph; +class TFile; + +namespace o2 +{ + +class HistoManager : public TObjArray +{ + public: + HistoManager(const std::string& dirname = "", const std::string& fname = "histoman.root", bool load = kFALSE, const std::string& prefix = ""); + ~HistoManager() override { Delete(); } + + HistoManager* createClone(const std::string& prefix) const; + void addPrefix(const std::string& pref = ""); + + int getNHistos() const { return mNHistos; } + TGraph* getGraph(int id) const; + TH1* getHisto(int id) const; + TH1* getHisto(const std::string& name) const; + TH1F* getHisto1F(int id) const; + TH2F* getHisto2F(int id) const; + TProfile* getHistoP(int id) const; + + int addHisto(TH1* histo, int at = -1); + int addGraph(TGraph* gr, int at = -1); + void delHisto(int at); + + void setFile(TFile* file); + void setFileName(const std::string& fname); + const std::string& getFileName() const { return mDefName; } + void setDirName(const std::string& name) { mDirName = name; } + const std::string& getDirName() const { return mDirName; } + + void reset(); + void write(TFile* file = nullptr); + int write(const std::string& flname) + { + setFileName(flname); + write(); + return 0; + } + + void addHistos(const HistoManager* hm, Double_t c1 = 1.); + void divideHistos(const HistoManager* hm); + void multiplyHistos(const HistoManager* hm); + void scaleHistos(Double_t c1 = 1.); + void setColor(int tcolor = 1); + void setMarkerStyle(Style_t mstyle = 1, Size_t msize = 1); + void setMarkerSize(Size_t msize = 1); + void sumw2(); + int load(const std::string& fname, const std::string& dirname = ""); + + void purify(bool emptyToo = kFALSE); + + void Print(Option_t* option = "") const override; + void Clear(Option_t* option = "") override; + void Delete(Option_t* option = "") override; + void Compress() override; + + private: + int mNHistos{0}; //! Number of histograms defined + std::string mDefName{}; //! Default file name + std::string mDirName{}; //! Directory name in the output file + + ClassDefOverride(HistoManager, 0); +}; + +} // namespace o2 + +#endif // _O2_HISTOMANAGER_H_ diff --git a/Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx b/Detectors/GlobalTrackingWorkflow/study/src/CheckResidSpec.cxx similarity index 50% rename from Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx rename to Detectors/GlobalTrackingWorkflow/study/src/CheckResidSpec.cxx index dc002489c24e2..6f3055aa00806 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/CheckResidSpec.cxx @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "GlobalTrackingStudy/CheckResid.h" +#include "GlobalTrackingStudy/CheckResidSpec.h" #include "GlobalTrackingStudy/CheckResidTypes.h" #include "GlobalTrackingStudy/CheckResidConfig.h" #include @@ -27,6 +27,7 @@ #include "SimulationDataFormat/MCUtils.h" #include "CommonUtils/NameConf.h" #include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" #include "Framework/CCDBParamSpec.h" #include "Framework/DeviceSpec.h" #include "DataFormatsITSMFT/DPLAlpideParam.h" @@ -38,6 +39,18 @@ #include "CommonUtils/TreeStreamRedirector.h" #include "ReconstructionDataFormats/VtxTrackRef.h" #include "DetectorsVertexing/PVertexer.h" +#include "GlobalTrackingStudy/HistoManager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifdef WITH_OPENMP #include #endif @@ -62,14 +75,9 @@ using timeEst = o2::dataformats::TimeStampWithError; class CheckResidSpec : public Task { public: - CheckResidSpec(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool useMC /*, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts*/) - : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mUseMC(useMC) + CheckResidSpec(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool drawOnly) + : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mDrawOnly(drawOnly) { - /* - mTPCCorrMapsLoader.setLumiScaleType(sclOpts.lumiType); - mTPCCorrMapsLoader.setLumiScaleMode(sclOpts.lumiMode); - mTPCCorrMapsLoader.setCheckCTPIDCConsistency(sclOpts.checkCTPIDCconsistency); - */ } ~CheckResidSpec() final = default; void init(InitContext& ic) final; @@ -83,6 +91,10 @@ class CheckResidSpec : public Task bool refitPV(o2::dataformats::PrimaryVertex& pv, int vid); bool refitITStrack(o2::track::TrackParCov& track, GTrackID gid); bool processITSTrack(const o2::its::TrackITS& iTrack, const o2::dataformats::PrimaryVertex& pv, o2::checkresid::Track& resTrack); + void bookHistos(); + void fillHistos(const o2::checkresid::Track& trc); + void postProcessHistos(); + void drawHistos(); o2::globaltracking::RecoContainer* mRecoData = nullptr; int mNThreads = 1; @@ -94,30 +106,85 @@ class CheckResidSpec : public Task o2::vertexing::PVertexer mVertexer; std::shared_ptr mDataRequest; std::shared_ptr mGGCCDBRequest; - bool mUseMC{false}; ///< MC flag std::unique_ptr mDBGOut; GTrackID::mask_t mTracksSrc{}; + + bool mDrawOnly = false; + bool mDraw = false; + bool mFillHistos = true; + bool mFillTree = true; + std::vector> mHManV{}; + o2::HistoManager* mHMan = nullptr; }; void CheckResidSpec::init(InitContext& ic) { - o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); + mDraw = true; + if (!mDrawOnly) { + mDraw = ic.options().get("draw-report"); + mFillHistos = !ic.options().get("no-hist"); + mFillTree = !ic.options().get("no-tree"); + mNThreads = ic.options().get("nthreads"); + } + const auto& params = o2::checkresid::CheckResidConfig::Instance(); int lane = ic.services().get().inputTimesliceId; int maxLanes = ic.services().get().maxInputTimeslices; - std::string dbgnm = maxLanes == 1 ? "checkResid.root" : fmt::format("checkResid_t{}.root", lane); - mDBGOut = std::make_unique(dbgnm.c_str(), "recreate"); - mNThreads = ic.options().get("nthreads"); + std::string nm = params.outname; + if (maxLanes > 1) { + o2::conf::ConfigurableParam::updateFromString(fmt::format("checkresid.outname={}_{}", nm, lane)); + } + if (mDraw) { + mFillHistos = true; + } + if (!mDrawOnly && mFillHistos) { + bookHistos(); + } + if (!params.ext_hm_list.empty()) { + auto vecNames = o2::utils::Str::tokenize(params.ext_hm_list, ','); + auto vecLegends = o2::utils::Str::tokenize(params.ext_leg_list, ','); + bool useLeg = true; + if (vecNames.size() != vecLegends.size()) { + LOGP(warn, "{} legend names provided for {} external histomanagers, will use file names as legends", vecLegends.size(), vecNames.size()); + useLeg = false; + } + int cntH = 0; + for (const auto& vn : vecNames) { + LOGP(info, "Loading external HistoManager {}", vn); + mHManV.emplace_back() = std::make_unique("", vn, true); + auto hm = mHManV.back().get(); + if (!hm) { + LOGP(error, "Failed to load histograms from {}", vn); + mHManV.pop_back(); + } else { + hm->SetName(useLeg ? vecLegends[cntH].c_str() : vn.c_str()); + } + cntH++; + } + } + if (mDrawOnly) { + return; + } + o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); #ifndef WITH_OPENMP if (mNThreads > 1) { LOGP(warn, "No OpenMP"); } mNThreads = 1; #endif - // mTPCCorrMapsLoader.init(ic); + if (mFillTree) { + nm += ".root"; + mDBGOut = std::make_unique(nm.c_str(), "recreate"); + } } void CheckResidSpec::run(ProcessingContext& pc) { + if (mDrawOnly) { + drawHistos(); + pc.services().get().endOfStream(); + pc.services().get().readyToQuit(QuitRequest::Me); + return; + } o2::globaltracking::RecoContainer recoData; mRecoData = &recoData; mRecoData->collectData(pc, *mDataRequest.get()); // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer @@ -131,8 +198,6 @@ void CheckResidSpec::updateTimeDependentParams(ProcessingContext& pc) { o2::base::GRPGeomHelper::instance().checkUpdates(pc); pc.inputs().get("meanvtx"); - // mTPCVDriftHelper.extractCCDBInputs(pc); - // mTPCCorrMapsLoader.extractCCDBInputs(pc); static bool initOnceDone = false; if (!initOnceDone) { // this params need to be queried only once const auto& params = o2::checkresid::CheckResidConfig::Instance(); @@ -155,24 +220,6 @@ void CheckResidSpec::updateTimeDependentParams(ProcessingContext& pc) mVertexer.setMeanVertex(&mMeanVtx); mVertexer.initMeanVertexConstraint(); } - bool updateMaps = false; - /* - if (mTPCCorrMapsLoader.isUpdated()) { - mTPCCorrMapsLoader.acknowledgeUpdate(); - updateMaps = true; - } - if (mTPCVDriftHelper.isUpdated()) { - LOGP(info, "Updating TPC fast transform map with new VDrift factor of {} wrt reference {} and DriftTimeOffset correction {} wrt {} from source {}", - mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, - mTPCVDriftHelper.getVDriftObject().timeOffsetCorr, mTPCVDriftHelper.getVDriftObject().refTimeOffset, - mTPCVDriftHelper.getSourceName()); - mTPCVDriftHelper.acknowledgeUpdate(); - updateMaps = true; - } - if (updateMaps) { - mTPCCorrMapsLoader.updateVDrift(mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getVDriftObject().getTimeOffset()); - } - */ } void CheckResidSpec::process() @@ -249,14 +296,18 @@ void CheckResidSpec::process() continue; } const auto& trc = mRecoData->getTrackParam(vid); + const auto& itsTrack = mRecoData->getITSTrack(gidITS); + if (itsTrack.getNClusters() < params.minITSCl) { + continue; + } auto pt = trc.getPt(); if (pt < params.minPt || pt > params.maxPt) { continue; } - const auto& itsTrack = mRecoData->getITSTrack(gidITS); - if (itsTrack.getNClusters() < params.minITSCl) { + if (std::abs(trc.getTgl()) > params.maxTgl) { continue; } + #ifdef WITH_OPENMP auto& accum = slots[omp_get_thread_num()]; #else @@ -275,6 +326,9 @@ void CheckResidSpec::process() for (const auto& accum : slots) { for (const auto& tr : accum) { (*mDBGOut) << "res" << "tr=" << tr << "\n"; + if (mHMan) { + fillHistos(tr); + } } } LOGP(info, "processed {} PVs out of {} good vertices (out of {} in total), PV refits took {} mus, {} refits failed", nvUse, nvGood, nv, pvFitDuration, nvRefFail); @@ -439,10 +493,10 @@ bool CheckResidSpec::refitPV(o2::dataformats::PrimaryVertex& pv, int vid) auto trackIndex = mRecoData->getPrimaryVertexMatchedTracks(); int itr = vtref.getFirstEntry(), itLim = itr + vtref.getEntries(); for (; itr < itLim; itr++) { - auto vid = trackIndex[itr]; - if (vid.isPVContributor()) { - tracks.emplace_back().setPID(mRecoData->getTrackParam(vid).getPID()); - gidsITS.push_back(mRecoData->getITSContributorGID(vid)); + auto tid = trackIndex[itr]; + if (tid.isPVContributor() && mRecoData->isTrackSourceLoaded(tid.getSource())) { + tracks.emplace_back().setPID(mRecoData->getTrackParam(tid).getPID()); + gidsITS.push_back(mRecoData->getITSContributorGID(tid)); } } ntr = tracks.size(); @@ -507,9 +561,345 @@ bool CheckResidSpec::refitITStrack(o2::track::TrackParCov& track, GTrackID gid) return true; } +void CheckResidSpec::fillHistos(const o2::checkresid::Track& trc) +{ + const auto& params = CheckResidConfig::Instance(); + int np = trc.points.size(); + auto pt = trc.track.getPt(); + if (pt < params.minPt || pt > params.maxPt) { + return; + } + for (int ip = 0; ip < np; ip++) { + const auto& pnt = trc.points[ip]; + int il = pnt.lr >= 0 ? pnt.lr + 1 : 0; + mHMan->getHisto2F(il * 10 + 0 * 100)->Fill(pnt.phi, pnt.dy); + mHMan->getHisto2F(il * 10 + 0 * 100 + 1000)->Fill(pnt.z, pnt.dy); + mHMan->getHisto2F(il * 10 + 0 * 100 + 2000)->Fill(pt, pnt.dy); + mHMan->getHisto2F(il * 10 + 0 * 100 + 3000)->Fill(trc.track.getTgl(), pnt.dy); + if (pnt.sig2y > 0) { + auto pull = pnt.dy / std::sqrt(pnt.sig2y); + mHMan->getHisto2F(il * 10 + 0 * 100 + 5)->Fill(pnt.phi, pull); + mHMan->getHisto2F(il * 10 + 0 * 100 + 5 + 1000)->Fill(pnt.z, pull); + mHMan->getHisto2F(il * 10 + 0 * 100 + 5 + 2000)->Fill(pt, pull); + mHMan->getHisto2F(il * 10 + 0 * 100 + 5 + 3000)->Fill(trc.track.getTgl(), pull); + } + mHMan->getHisto2F(il * 10 + 1 * 100)->Fill(pnt.phi, pnt.dz); + mHMan->getHisto2F(il * 10 + 1 * 100 + 1000)->Fill(pnt.z, pnt.dz); + mHMan->getHisto2F(il * 10 + 1 * 100 + 2000)->Fill(pt, pnt.dz); + mHMan->getHisto2F(il * 10 + 1 * 100 + 3000)->Fill(trc.track.getTgl(), pnt.dz); + if (pnt.sig2z > 0) { + auto pull = pnt.dz / std::sqrt(pnt.sig2z); + mHMan->getHisto2F(il * 10 + 1 * 100 + 5)->Fill(pnt.phi, pull); + mHMan->getHisto2F(il * 10 + 1 * 100 + 5 + 1000)->Fill(pnt.z, pull); + mHMan->getHisto2F(il * 10 + 1 * 100 + 5 + 2000)->Fill(pt, pull); + mHMan->getHisto2F(il * 10 + 1 * 100 + 5 + 3000)->Fill(trc.track.getTgl(), pull); + } + } + //-------------- + if (trc.trIBOut.getX() > 1 && std::abs(trc.trIBOut.getX() - trc.trOBInw.getX()) < 0.1) { + for (int ip = 0; ip < 5; ip++) { + float d = trc.trIBOut.getParam(ip) - trc.trOBInw.getParam(ip); + mHMan->getHisto2F(10000 + ip * 10)->Fill(trc.trIBOut.getPhiPos(), d); + mHMan->getHisto2F(11000 + ip * 10)->Fill(trc.trIBOut.getZ(), d); + mHMan->getHisto2F(12000 + ip * 10)->Fill(pt, d); + mHMan->getHisto2F(13000 + ip * 10)->Fill(trc.track.getTgl(), d); + float sg = trc.trIBOut.getCovarElem(ip, ip) + trc.trOBInw.getCovarElem(ip, ip); + if (sg > 0) { + auto pull = d / std::sqrt(sg); + mHMan->getHisto2F(10000 + ip * 10 + 5)->Fill(trc.trIBOut.getPhiPos(), pull); + mHMan->getHisto2F(11000 + ip * 10 + 5)->Fill(trc.trIBOut.getZ(), pull); + mHMan->getHisto2F(12000 + ip * 10 + 5)->Fill(pt, pull); + mHMan->getHisto2F(13000 + ip * 10 + 5)->Fill(trc.track.getTgl(), pull); + } + } + } +} + +void CheckResidSpec::bookHistos() +{ + const auto& params = o2::checkresid::CheckResidConfig::Instance(); + mHManV.emplace_back() = std::make_unique("", fmt::format("{}_hman.root", params.outname)); + mHMan = mHManV.back().get(); + mHMan->SetName(params.outname.c_str()); + auto defLogAxis = [](float xMn, float xMx, int nbin) { // get array for log axis + if (xMn <= 0 || xMx <= xMn || nbin < 2) { + LOGP(fatal, "Wrong log axis request: xmin = {} xmax = {} nbins = {}", xMn, xMx, nbin); + } + auto dx = std::log(xMx / xMn) / nbin; + std::vector xax(nbin + 1); + for (int i = 0; i <= nbin; i++) { + xax[i] = xMn * std::exp(dx * i); + } + return xax; + }; + float minPt = std::max(0.1f, params.minPt), maxPt = std::min(50.f, params.maxPt); + auto ptax = defLogAxis(minPt, maxPt, params.nBinsPt); + + for (int il = 0; il < 8; il++) { + std::string lrName = il == 0 ? "Vtx" : fmt::format("Lr{}", il - 1); + for (int iyz = 0; iyz < 2; iyz++) { + std::string dname = iyz == 0 ? "dy" : "dz", dtit = iyz == 0 ? "#DeltaY" : "#DeltaZ"; + auto h2 = new TH2F(fmt::format("{}_{}_{}", dname, lrName, "phi").c_str(), fmt::format("{}_{{{}}} vs {};#phi;{}", dtit, lrName, "#phi", dtit).c_str(), params.nBinsPhi, 0, TMath::Pi() * 2, params.nBinsRes, -params.maxDYZ[il], params.maxDYZ[il]); + mHMan->addHisto(h2, il * 10 + iyz * 100); + auto h2p = new TH2F(fmt::format("{}_{}_{}_pull", dname, lrName, "phi").c_str(), fmt::format("pull {}_{{{}}} vs {};#phi; pull{}", dtit, lrName, "phi", dtit).c_str(), params.nBinsPhi, 0, TMath::Pi() * 2, params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(h2p, il * 10 + iyz * 100 + 5); + + auto hz2 = new TH2F(fmt::format("{}_{}_{}", dname, lrName, "Z").c_str(), fmt::format("{}_{{{}}} vs {};Z;{}", dtit, lrName, "Z", dtit).c_str(), params.nBinsZ, -params.zranges[il], params.zranges[il], params.nBinsRes, -params.maxDYZ[il], params.maxDYZ[il]); + mHMan->addHisto(hz2, il * 10 + iyz * 100 + 1000); + auto hz2p = new TH2F(fmt::format("{}_{}_{}_pull", dname, lrName, "Z").c_str(), fmt::format("pull {}_{{{}}} vs {};Z; pull{}", dtit, lrName, "Z", dtit).c_str(), params.nBinsZ, -params.zranges[il], params.zranges[il], params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(hz2p, il * 10 + iyz * 100 + 5 + 1000); + + auto hpt2 = new TH2F(fmt::format("{}_{}_{}", dname, lrName, "Pt").c_str(), fmt::format("{}_{{{}}} vs {};p_{{T}};{}", dtit, lrName, "p_{T}", dtit).c_str(), params.nBinsPt, ptax.data(), params.nBinsRes, -params.maxDYZ[il], params.maxDYZ[il]); + mHMan->addHisto(hpt2, il * 10 + iyz * 100 + 2000); + auto hpt2p = new TH2F(fmt::format("{}_{}_{}_pull", dname, lrName, "Pt").c_str(), fmt::format("pull {}_{{{}}} vs {};p_{{T}}; pull{}", dtit, lrName, "p_{T}", dtit).c_str(), params.nBinsPt, ptax.data(), params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(hpt2p, il * 10 + iyz * 100 + 5 + 2000); + + auto htgl2 = new TH2F(fmt::format("{}_{}_{}", dname, lrName, "tgl").c_str(), fmt::format("{}_{{{}}} vs {};tg#lambda;{}", dtit, lrName, "tg#lambda", dtit).c_str(), params.nBinsTgl, -params.maxTgl, params.maxTgl, params.nBinsRes, -params.maxDYZ[il], params.maxDYZ[il]); + mHMan->addHisto(htgl2, il * 10 + iyz * 100 + 3000); + auto htgl2p = new TH2F(fmt::format("{}_{}_{}_pull", dname, lrName, "tgl").c_str(), fmt::format("pull {}_{{{}}} vs {};tg#lambda; pull{}", dtit, lrName, "tg#lambda", dtit).c_str(), params.nBinsTgl, -params.maxTgl, params.maxTgl, params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(htgl2p, il * 10 + iyz * 100 + 5 + 3000); + } + } + + for (int ip = 0; ip < 5; ip++) { + auto h2 = new TH2F(fmt::format("dPar{}_IBOBphi", ip).c_str(), fmt::format("#Delta par{} IB-OB vs phi;#phi;#Delta par{}", ip, ip).c_str(), params.nBinsPhi, 0, TMath::Pi() * 2, params.nBinsRes, -params.maxDPar[ip], params.maxDPar[ip]); + mHMan->addHisto(h2, 10000 + ip * 10); + auto h2p = new TH2F(fmt::format("dPar{}_IBOBphi_pull", ip).c_str(), fmt::format("pull #Delta par{} IB-OB vs phi;#phi;pull #Delta par{}", ip, ip).c_str(), params.nBinsPhi, 0, TMath::Pi() * 2, params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(h2p, 10000 + ip * 10 + 5); + + auto hz2 = new TH2F(fmt::format("dPar{}_IBOBz", ip).c_str(), fmt::format("#Delta par{} IB-OB vs Z;Z;#Delta par{}", ip, ip).c_str(), params.nBinsZ, -20., 20., params.nBinsRes, -params.maxDPar[ip], params.maxDPar[ip]); + mHMan->addHisto(hz2, 11000 + ip * 10); + auto hz2p = new TH2F(fmt::format("dPar{}_IBOBz_pull", ip).c_str(), fmt::format("pull #Delta par{} IB-OB vs Z;Z;pull #Delta par{}", ip, ip).c_str(), params.nBinsZ, -20., 20., params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(hz2p, 11000 + ip * 10 + 5); + + auto hpt2 = new TH2F(fmt::format("dPar{}_IBOBpt", ip).c_str(), fmt::format("#Delta par{} IB-OB vs pT;p_{{T}};#Delta par{}", ip, ip).c_str(), params.nBinsPt, ptax.data(), params.nBinsRes, -params.maxDPar[ip], params.maxDPar[ip]); + mHMan->addHisto(hpt2, 12000 + ip * 10); + auto hpt2p = new TH2F(fmt::format("dPar{}_IBOBpt_pull", ip).c_str(), fmt::format("pull #Delta par{} IB-OB vs pT;p_{{T}};pull #Delta par{}", ip, ip).c_str(), params.nBinsPt, ptax.data(), params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(hpt2p, 12000 + ip * 10 + 5); + + auto htgl2 = new TH2F(fmt::format("dPar{}_IBOBtgl", ip).c_str(), fmt::format("#Delta par{} IB-OB vs tg#lambda;tg#lambda;#Delta par{}", ip, ip).c_str(), params.nBinsTgl, -params.maxTgl, params.maxTgl, params.nBinsRes, -params.maxDPar[ip], params.maxDPar[ip]); + mHMan->addHisto(htgl2, 13000 + ip * 10); + auto htgl2p = new TH2F(fmt::format("dPar{}_IBOBtgl_pull", ip).c_str(), fmt::format("pull #Delta par{} IB-OB vs tg#lambda;tg#lambda;pull #Delta par{}", ip, ip).c_str(), params.nBinsTgl, -params.maxTgl, params.maxTgl, params.nBinsRes, -params.maxPull, params.maxPull); + mHMan->addHisto(htgl2p, 13000 + ip * 10 + 5); + } +} + +void CheckResidSpec::postProcessHistos() +{ + printf("Fitting histos\n"); + const auto& params = o2::checkresid::CheckResidConfig::Instance(); + auto gs = new TF1("gs", "gaus", -1, 1); + TObjArray arr; + auto* histm = mHMan; + auto fitSlices = [&](int id) { + auto h2 = histm->getHisto2F(id); + if (!h2 || h2->GetEntries() < params.minHistoStat2Fit) { + return; + } + h2->FitSlicesY(gs, 0, -1, 0, "QNR", &arr); + arr.SetOwner(true); + TH1* hmean = (TH1*)arr.RemoveAt(1); + if (hmean) { + hmean->SetTitle(Form("<%s>", h2->GetTitle())); + histm->addHisto(hmean, id + 1); + } + TH1* hsig = (TH1*)arr.RemoveAt(2); + if (hsig) { + hsig->SetTitle(Form("#sigma(%s)", h2->GetTitle())); + histm->addHisto(hsig, id + 2); + } + }; + for (int ioffs = 0; ioffs <= 3; ioffs++) { // vs phi, Z, pT, tgl + int offs = ioffs * 1000; + for (int iht = 0; iht < 2; iht++) { // resid, pull + int offsV = iht == 0 ? 0 : 5; + for (int il = 0; il < 8; il++) { + for (int iyz = 0; iyz < 2; iyz++) { + fitSlices(il * 10 + iyz * 100 + offsV + offs); + } + } + for (int ip = 0; ip < 5; ip++) { + fitSlices(10000 + ip * 10 + offsV + offs); + } + } + } + histm->write(); + delete gs; +} + +void CheckResidSpec::drawHistos() +{ + gROOT->SetBatch(true); + gStyle->SetTitleX(0.2); + gStyle->SetTitleY(0.88); + gStyle->SetTitleW(0.25); + gStyle->SetOptStat(0); + int nhm = mHManV.size(); + std::array hcol{EColor::kRed, EColor::kBlue, EColor::kGreen + 2}; + std::unique_ptr lg; + lg = std::make_unique(0.12, 0.13, 0.9, 0.13 + std::min(0.5f, nhm * 0.2f / 3.f)); + lg->SetFillStyle(0); + lg->SetBorderSize(0); + for (int i = 0; i < nhm; i++) { + auto hman = mHManV[i].get(); + if (!hman || hman->GetLast() < 1) { + continue; + } + hman->setMarkerStyle(20 + i + (i % 2) * 4, 0.5); + hman->setColor(hcol[i % hcol.size()]); + auto le = lg->AddEntry(hman->getHisto(1), hman->GetName(), "lp"); + le->SetTextColor(hcol[i % hcol.size()]); + } + TCanvas cly("cly", "", 600, 800), clz("clz", "", 600, 800), clpar("clpar", "", 600, 800); + TCanvas czly("czly", "", 600, 800), czlz("czlz", "", 600, 800), czlpar("czlpar", "", 600, 800); + const auto& params = o2::checkresid::CheckResidConfig::Instance(); + + auto AddLabel = [](const char* txt, float x = 0.1, float y = 0.9, int color = kBlack, float size = 0.04) { + TLatex* lt = new TLatex(x, y, txt); + lt->SetNDC(); + lt->SetTextColor(color); + lt->SetTextSize(size); + lt->Draw(); + return lt; + }; + + auto drawResLr = [this](TCanvas& canv, int offs, const float resMM[8], bool logX) { + canv.Clear(); + canv.Divide(2, 4); + int nh = this->mHManV.size(); + for (int i = 0; i < 8; i++) { + canv.cd(i + 1); + bool same = false; + for (int j = 0; j < nh; j++) { + auto hman = this->mHManV[j].get(); + if (!hman || hman->GetLast() < 1) { + continue; + } + if (auto histo = hman->getHisto(10 * i + offs)) { + histo->Draw(same ? "same" : ""); + if (!same) { + histo->SetMinimum(-resMM[i]); + histo->SetMaximum(resMM[i]); + same = true; + } + } + } + gPad->SetGrid(); + gPad->SetLogx(logX); + } + }; + + auto drawResPar = [this](TCanvas& canv, int offs, const float resMM[8], bool logX) { + canv.Clear(); + canv.Divide(2, 3); + int nh = this->mHManV.size(); + for (int i = 0; i < 5; i++) { + canv.cd(i + 1); + bool same = false; + for (int j = 0; j < nh; j++) { + auto hman = this->mHManV[j].get(); + if (!hman || hman->GetLast() < 1) { + continue; + } + if (auto histo = hman->getHisto(10 * i + offs)) { + histo->Draw(same ? "same" : ""); + if (!same) { + histo->SetMinimum(-resMM[i]); + histo->SetMaximum(resMM[i]); + same = true; + } + } + } + gPad->SetGrid(); + gPad->SetLogx(logX); + } + }; + + cly.Print(Form("%s_hman.pdf[", params.outname.c_str())); + drawResLr(cly, 1, params.resMMLrY, false); + cly.cd(2); + lg->Draw(); + AddLabel("Y residuals", 0.1, 0.95); + cly.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResLr(clz, 101, params.resMMLrZ, false); + clz.cd(2); + lg->Draw(); + AddLabel("Z residuals", 0.1, 0.95); + clz.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResLr(czly, 1001, params.resMMLrY, false); + czly.cd(2); + lg->Draw(); + AddLabel("Y residuals", 0.1, 0.95); + czly.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResLr(czlz, 1101, params.resMMLrZ, false); + czlz.cd(2); + lg->Draw(); + AddLabel("Z residuals", 0.1, 0.95); + czlz.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResLr(czly, 2001, params.resMMLrY, true); + czly.cd(2); + lg->Draw(); + AddLabel("Y residuals", 0.1, 0.95); + czly.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResLr(czlz, 2101, params.resMMLrZ, true); + czlz.cd(2); + lg->Draw(); + AddLabel("Z residuals", 0.1, 0.95); + czlz.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResLr(czly, 3001, params.resMMLrY, false); + czly.cd(2); + lg->Draw(); + AddLabel("Y residuals", 0.1, 0.95); + czly.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResLr(czlz, 3101, params.resMMLrZ, false); + czlz.cd(2); + lg->Draw(); + AddLabel("Z residuals", 0.1, 0.95); + czlz.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResPar(clpar, 10001, params.resMMPar, false); + clpar.cd(6); + lg->Draw(); + AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8); + clpar.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResPar(czlpar, 11001, params.resMMPar, false); + czlpar.cd(6); + lg->Draw(); + AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8); + czlpar.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResPar(czlpar, 12001, params.resMMPar, true); + czlpar.cd(6); + lg->Draw(); + AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8); + czlpar.Print(Form("%s_hman.pdf", params.outname.c_str())); + + drawResPar(czlpar, 13001, params.resMMPar, false); + czlpar.cd(6); + lg->Draw(); + AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8); + czlpar.Print(Form("%s_hman.pdf", params.outname.c_str())); + + cly.Print(Form("%s_hman.pdf]", params.outname.c_str())); +} + void CheckResidSpec::endOfStream(EndOfStreamContext& ec) { mDBGOut.reset(); + if (mHManV.size()) { + postProcessHistos(); + } + if (mDraw) { + drawHistos(); + } } void CheckResidSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) @@ -517,14 +907,6 @@ void CheckResidSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { return; } - /* - if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) { - return; - } - if (mTPCCorrMapsLoader.accountCCDBInputs(matcher, obj)) { - return; - } - */ if (matcher == ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) { LOG(info) << "Imposing new MeanVertex: " << ((const o2::dataformats::MeanVertexObject*)obj)->asString(); mMeanVtx = *(const o2::dataformats::MeanVertexObject*)obj; @@ -538,33 +920,39 @@ void CheckResidSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) } } -DataProcessorSpec getCheckResidSpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool useMC /*, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts*/) +DataProcessorSpec getCheckResidSpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool drawOnly) { std::vector outputs; auto dataRequest = std::make_shared(); - dataRequest->requestTracks(srcTracks, useMC); - dataRequest->requestClusters(srcClusters, useMC); - dataRequest->requestPrimaryVertices(useMC); - auto ggRequest = std::make_shared(false, // orbitResetTime - true, // GRPECS=true - true, // GRPLHCIF - true, // GRPMagField - true, // askMatLUT - o2::base::GRPGeomRequest::Aligned, // geometry - dataRequest->inputs, - true); - dataRequest->inputs.emplace_back("meanvtx", "GLO", "MEANVERTEX", 0, Lifetime::Condition, ccdbParamSpec("GLO/Calib/MeanVertex", {}, 1)); - Options opts{ - {"nthreads", VariantType::Int, 1, {"number of threads"}}, - }; - // o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs); - // o2::tpc::CorrectionMapsLoader::requestCCDBInputs(dataRequest->inputs, opts, sclOpts); + if (!drawOnly) { + bool useMC = false; + dataRequest->requestTracks(srcTracks, useMC); + dataRequest->requestClusters(srcClusters, useMC); + dataRequest->requestPrimaryVertices(useMC); + dataRequest->inputs.emplace_back("meanvtx", "GLO", "MEANVERTEX", 0, Lifetime::Condition, ccdbParamSpec("GLO/Calib/MeanVertex", {}, 1)); + } + auto ggRequest = drawOnly ? std::make_shared(false, false, false, false, false, o2::base::GRPGeomRequest::None, dataRequest->inputs) : std::make_shared(false, // orbitResetTime + true, // GRPECS=true + true, // GRPLHCIF + true, // GRPMagField + true, // askMatLUT + o2::base::GRPGeomRequest::Aligned, // geometry + dataRequest->inputs, true); + Options opts; + if (!drawOnly) { + opts = Options{ + {"nthreads", VariantType::Int, 1, {"number of threads"}}, + {"no-tree", VariantType::Bool, false, {"do not fill residuals tree"}}, + {"no-hist", VariantType::Bool, false, {"do not fill residuals histograms"}}, + {"draw-report", VariantType::Bool, false, {"fill residuals report"}}, + }; + } return DataProcessorSpec{ "check-resid", dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, srcTracks, useMC /*, sclOpts*/)}, + AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, srcTracks, drawOnly)}, opts}; } diff --git a/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h b/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h index 416820fc9aebb..b1fe732fbefc4 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h +++ b/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h @@ -49,4 +49,6 @@ #pragma link C++ class o2::checkresid::CheckResidConfig + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::checkresid::CheckResidConfig> + ; +#pragma link C++ class o2::HistoManager + ; + #endif diff --git a/Detectors/GlobalTrackingWorkflow/study/src/HistoManager.cxx b/Detectors/GlobalTrackingWorkflow/study/src/HistoManager.cxx new file mode 100644 index 0000000000000..e57a78e4b202d --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/src/HistoManager.cxx @@ -0,0 +1,505 @@ +// Copyright 2019-2026 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Framework/Logger.h" +#include "GlobalTrackingStudy/HistoManager.h" + +namespace o2 +{ + +HistoManager::HistoManager(const std::string& dirname, const std::string& fname, bool load, const std::string& prefix) : mDirName(dirname) +{ + setFileName(fname); + if (load && !mDefName.empty()) { + int nh = this->load(fname, dirname); + LOGP(info, "HistoManager::load was requested: got {} histos from {}/{}", nh, fname, dirname); + if (!prefix.empty()) { + addPrefix(prefix); + } + } +} + +HistoManager* HistoManager::createClone(const std::string& prefix) const +{ + auto* hm = static_cast(Clone()); + hm->addPrefix(prefix); + for (int i = 0; i < GetLast() + 1; ++i) { + TObject* obj = hm->UncheckedAt(i); + if (!obj) { + continue; + } + if (auto* histo = dynamic_cast(obj)) { + histo->SetDirectory(nullptr); + } + } + hm->mNHistos = mNHistos; + hm->setFileName(mDefName); + hm->setDirName(mDirName); + return hm; +} + +int HistoManager::addHisto(TH1* histo, int at) +{ + if (!histo) { + return mNHistos; + } + if (at < 0) { + at = mNHistos; + } + AddAtAndExpand(histo, at); + histo->SetDirectory(nullptr); + histo->SetUniqueID(at + 1); + return mNHistos++; +} + +TGraph* HistoManager::getGraph(int id) const +{ + return id <= GetLast() ? dynamic_cast(UncheckedAt(id)) : nullptr; +} + +TH1* HistoManager::getHisto(int id) const +{ + return id <= GetLast() ? dynamic_cast(UncheckedAt(id)) : nullptr; +} + +TH1* HistoManager::getHisto(const std::string& name) const +{ + return dynamic_cast(FindObject(name.c_str())); +} + +TH1F* HistoManager::getHisto1F(int id) const +{ + return dynamic_cast(UncheckedAt(id)); +} + +TH2F* HistoManager::getHisto2F(int id) const +{ + return dynamic_cast(UncheckedAt(id)); +} + +TProfile* HistoManager::getHistoP(int id) const +{ + return dynamic_cast(UncheckedAt(id)); +} + +int HistoManager::addGraph(TGraph* gr, int at) +{ + if (!gr) { + return mNHistos; + } + if (at < 0) { + at = mNHistos; + } + AddAtAndExpand(gr, at); + gr->SetUniqueID(at + 1); + return mNHistos++; +} + +void HistoManager::Compress() +{ + TObjArray::Compress(); + for (int i = 0; i < GetLast() + 1; ++i) { + if (TObject* histo = At(i)) { + histo->SetUniqueID(i + 1); + } + } +} + +void HistoManager::write(TFile* file) +{ + if (!mNHistos) { + return; + } + + bool localFile = kFALSE; + TFile* lfile = nullptr; + const char* dirName = nullptr; + if (file) { + lfile = file; + } else { + auto* tmpF = static_cast(gROOT->GetListOfFiles()->FindObject(mDefName.c_str())); + if (tmpF && tmpF->IsOpen()) { + TString opt = tmpF->GetOption(); + opt.ToLower(); + if (!opt.Contains("read")) { + lfile = tmpF; + tmpF->cd(); + } + } + } + + TString pwd = gDirectory->GetPath(); + if (!lfile) { + std::string originalName = mDefName; + if (mDefName.empty() || mDefName[0] == ' ') { + mDefName = "histoman"; + } + TString rootName = mDefName.c_str(); + if (!rootName.Contains(".root")) { + mDefName += ".root"; + } + lfile = TFile::Open(mDefName.c_str(), "UPDATE"); + mDefName = originalName; + localFile = kTRUE; + } + + lfile->cd(); + dirName = mDirName.c_str(); + if (dirName && dirName[0] && dirName[0] != ' ') { + if (!lfile->Get(dirName)) { + lfile->mkdir(dirName); + } + lfile->cd(dirName); + } + LOGP(info, "Writing histograms to: {}/{}", lfile->GetPath(), dirName); + + for (int i = 0; i < GetLast() + 1; ++i) { + TObject* obj = UncheckedAt(i); + if (!obj) { + continue; + } + auto* histo = dynamic_cast(obj); + TDirectory* dr = nullptr; + if (histo) { + dr = histo->GetDirectory(); + histo->SetDirectory(nullptr); + } + obj->Write(nullptr, TObject::kOverwrite); + if (dr && histo) { + histo->SetDirectory(dr); + } + } + + if (localFile) { + lfile->Close(); + delete lfile; + } + auto* oldDir = static_cast(gROOT->GetListOfFiles()->FindObject(pwd.Data())); + if (oldDir) { + oldDir->cd(); + } +} + +void HistoManager::Clear(Option_t*) +{ + int nent = GetLast() + 1; + for (int i = 0; i < nent; ++i) { + TObject* hh = UncheckedAt(i); + if (!hh) { + continue; + } + RemoveAt(i); + --mNHistos; + } +} + +//_______________________________________________________________ +void HistoManager::Delete(Option_t*) +{ + int nent = GetLast() + 1; + for (int i = 0; i < nent; ++i) { + TObject* hh = UncheckedAt(i); + if (!hh) { + continue; + } + RemoveAt(i); + delete hh; + } + mNHistos = 0; +} + +void HistoManager::Print(Option_t* option) const +{ + int nent = GetLast() + 1; + for (int i = 0; i < nent; ++i) { + TObject* hh = UncheckedAt(i); + if (!hh) { + continue; + } + LOGP(info, "At position #{}", i); + hh->Print(option); + } + LOGP(info, "Total number of defined histograms: %d", mNHistos); + LOGP(info, "Current output path: {}/{}", mDefName, mDirName); +} + +void HistoManager::addPrefix(const std::string& pref) +{ + if (pref.empty()) { + return; + } + int nent = GetLast() + 1; + for (int i = 0; i < nent; ++i) { + TObject* hh = UncheckedAt(i); + if (!hh) { + continue; + } + if (hh->InheritsFrom("TNamed")) { + auto name = pref + hh->GetName(); + static_cast(hh)->SetName(name.c_str()); + } + } +} + +void HistoManager::addHistos(const HistoManager* hm, Double_t c1) +{ + if (!hm) { + return; + } + int nent = GetLast() + 1; + int nent1 = hm->GetLast() + 1; + if (nent != nent1) { + Error("addHistos", "HistoManagers have different content: %d vs %d", nent, nent1); + return; + } + for (int i = 0; i < nent; ++i) { + TH1* hh1 = getHisto(i); + TH1* hh2 = hm->getHisto(i); + if (!hh1 || !hh2) { + continue; + } + hh1->Add(hh2, c1); + } +} + +void HistoManager::divideHistos(const HistoManager* hm) +{ + if (!hm) { + return; + } + int nent = GetLast() + 1; + int nent1 = hm->GetLast() + 1; + if (nent != nent1) { + Error("divideHistos", "HistoManagers have different content: %d vs %d", nent, nent1); + return; + } + for (int i = 0; i < nent; ++i) { + TH1* hh1 = getHisto(i); + TH1* hh2 = hm->getHisto(i); + if (!hh1 || !hh2) { + continue; + } + hh1->Divide(hh2); + } +} + +//_______________________________________________________________ +void HistoManager::multiplyHistos(const HistoManager* hm) +{ + if (!hm) { + return; + } + int nent = GetLast() + 1; + int nent1 = hm->GetLast() + 1; + if (nent != nent1) { + Error("multiplyHistos", "HistoManagers have different content: %d vs %d", nent, nent1); + return; + } + for (int i = 0; i < nent; ++i) { + TH1* hh1 = getHisto(i); + TH1* hh2 = hm->getHisto(i); + if (!hh1 || !hh2) { + continue; + } + hh1->Multiply(hh2); + } +} + +void HistoManager::scaleHistos(Double_t c1) +{ + int nent = GetLast() + 1; + for (int i = 0; i < nent; ++i) { + TH1* hh1 = getHisto(i); + if (hh1) { + hh1->Scale(c1); + } + } +} + +void HistoManager::sumw2() +{ + int nent = GetLast() + 1; + for (int i = 0; i < nent; ++i) { + auto* hh1 = dynamic_cast(UncheckedAt(i)); + if (hh1) { + hh1->Sumw2(); + } + } +} + +void HistoManager::setFile(TFile* file) +{ + if (file) { + mDefName = file->GetName(); + } +} + +void HistoManager::delHisto(int at) +{ + TH1* hist = getHisto(at); + if (hist) { + RemoveAt(at); + delete hist; + --mNHistos; + } +} + +void HistoManager::purify(bool emptyToo) +{ + int last = GetLast() + 1; + if (emptyToo) { + for (int i = 0; i < last; ++i) { + TH1* hist = getHisto(i); + if (!hist) { + continue; + } + if (hist->GetEntries() < 1) { + delHisto(i); + } + } + } + Compress(); +} + +void HistoManager::setFileName(const std::string& name) +{ + mDefName = gSystem->ExpandPathName(name.c_str()); +} + +void HistoManager::reset() +{ + int last = GetLast() + 1; + for (int i = 0; i < last; ++i) { + TH1* hist = getHisto(i); + if (!hist) { + continue; + } + hist->Reset(); + } +} + +int HistoManager::load(const std::string& fname, const std::string& dirname) +{ + TFile* file = TFile::Open(gSystem->ExpandPathName(fname.c_str())); + if (!file) { + LOGP(error, "No file {}", fname); + return 0; + } + if (!dirname.empty() && dirname[0] != ' ') { + if (!file->Get(dirname.c_str())) { + LOGP(error, "No {} directory in file {}", dirname, fname); + file->Close(); + delete file; + return 0; + } + file->cd(dirname.c_str()); + } + int count = 0; + TList* lst = gDirectory->GetListOfKeys(); + TIter nextKey(lst); + TKey* key = nullptr; + while ((key = static_cast(nextKey()))) { + if (FindObject(key->GetName())) { + continue; + } + TString clName = key->GetClassName(); + if (!(clName.BeginsWith("TH") || clName.BeginsWith("TProfile") || clName.BeginsWith("TGraph"))) { + printf("Object %s of type %s is not processed\n", key->GetName(), clName.Data()); + continue; + } + TObject* hst = key->ReadObj(); + int id = hst->GetUniqueID(); + if (auto* h = dynamic_cast(hst)) { + addHisto(h, id - 1); + ++count; + continue; + } + if (auto* gr = dynamic_cast(hst)) { + addGraph(gr, id - 1); + ++count; + } + } + file->Close(); + delete file; + auto nm = fname; + if (!dirname.empty()) { + nm += fmt::format("/{}", dirname); + } + SetName(nm.c_str()); + return count; +} + +void HistoManager::setColor(int tcolor) +{ + int last = GetLast() + 1; + for (int i = 0; i < last; ++i) { + TH1* hist = getHisto(i); + if (!hist) { + continue; + } + hist->SetLineColor(tcolor); + hist->SetMarkerColor(tcolor); + TList* lst = hist->GetListOfFunctions(); + if (lst) { + int nf = lst->GetSize(); + for (int j = 0; j < nf; ++j) { + TObject* fnc = lst->At(j); + if (fnc->InheritsFrom("TF1")) { + static_cast(fnc)->SetLineColor(tcolor); + static_cast(fnc)->SetLineWidth(1); + static_cast(fnc)->ResetBit(TF1::kNotDraw); + } else if (fnc->InheritsFrom("TPaveStats")) { + static_cast(fnc)->SetTextColor(tcolor); + } + } + } + } +} + +void HistoManager::setMarkerStyle(Style_t mstyle, Size_t msize) +{ + int last = GetLast() + 1; + for (int i = 0; i < last; ++i) { + TH1* hist = getHisto(i); + if (!hist) { + continue; + } + hist->SetMarkerStyle(mstyle); + hist->SetMarkerSize(msize); + } +} + +void HistoManager::setMarkerSize(Size_t msize) +{ + int last = GetLast() + 1; + for (int i = 0; i < last; ++i) { + TH1* hist = getHisto(i); + if (!hist) { + continue; + } + hist->SetMarkerSize(msize); + } +} + +} // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/study/src/check-resid-workflow.cxx b/Detectors/GlobalTrackingWorkflow/study/src/check-resid-workflow.cxx index 86e4bb9ca234a..72188eb5f06c6 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/check-resid-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/check-resid-workflow.cxx @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "GlobalTrackingStudy/CheckResid.h" +#include "GlobalTrackingStudy/CheckResidSpec.h" #include "ReconstructionDataFormats/GlobalTrackID.h" #include "DetectorsCommonDataFormats/DetID.h" #include "CommonUtils/ConfigurableParam.h" @@ -20,8 +20,6 @@ #include "DetectorsBase/DPLWorkflowUtils.h" #include "GlobalTrackingWorkflowHelpers/InputHelper.h" #include "DetectorsRaw/HBFUtilsInitializer.h" -#include "TPCCalibration/CorrectionMapsOptions.h" -#include "TPCWorkflow/TPCScalerSpec.h" #include "DataFormatsITSMFT/DPLAlpideParamInitializer.h" using namespace o2::framework; @@ -39,14 +37,13 @@ void customize(std::vector& workflowOptions) { // option allowing to set parameters std::vector options{ - {"enable-mc", o2::framework::VariantType::Bool, false, {"enable MC propagation"}}, + {"draw-external-only", VariantType::Bool, false, {"just draw content of comma-separated list of histomanagers from checkresid.ext_hm_list"}}, {"track-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of track sources to use"}}, {"cluster-sources", VariantType::String, "ITS", {"comma-separated list of cluster sources to use"}}, {"disable-root-input", VariantType::Bool, false, {"disable root-files input reader"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; - // o2::tpc::CorrectionMapsLoader::addGlobalOptions(options); + o2::itsmft::DPLAlpideParamInitializer::addITSConfigOption(options); - o2::tpc::CorrectionMapsOptions::addGlobalOptions(options); o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -59,23 +56,30 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { WorkflowSpec specs; + bool drawOnly = configcontext.options().get("draw-external-only"); + GID::mask_t allowedSourcesTrc = GID::getSourcesMask("ITS,TPC,ITS-TPC,ITS-TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD-TOF"); GID::mask_t allowedSourcesClus = GID::getSourcesMask("ITS"); // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); - auto sclOpt = o2::tpc::CorrectionMapsOptions::parseGlobalOptions(configcontext.options()); - auto useMC = configcontext.options().get("enable-mc"); GID::mask_t srcTrc = allowedSourcesTrc & GID::getSourcesMask(configcontext.options().get("track-sources")); GID::mask_t srcCls = allowedSourcesClus & GID::getSourcesMask(configcontext.options().get("cluster-sources")); - 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::checkresid::getCheckResidSpec(srcTrc, srcCls, useMC)); + if (!drawOnly) { + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, false); + o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, false); // P-vertex is always needed + } else { + allowedSourcesTrc = {}; + allowedSourcesClus = {}; + } + specs.emplace_back(o2::checkresid::getCheckResidSpec(srcTrc, srcCls, drawOnly)); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit - o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + if (!drawOnly) { + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + } return std::move(specs); }