diff --git a/macro/reco/reco_steer.C b/macro/reco/reco_steer.C index 1fc55ceec3e590049c8579a74c54b14cea58c588..c3d4872b9998def99f52290984171c4e34f15141 100644 --- a/macro/reco/reco_steer.C +++ b/macro/reco/reco_steer.C @@ -24,6 +24,7 @@ using std::string; ** @param tsaFile Name of input file (w/o extension .tsa) ** @param outFile Name of output file (w/o extension .digi.root) ** @param numTs Number of timeslices to process. If not specified, all available will be used. + ** @param port Port of http server. If 0, server will not be activated. ** ** Reconstruction from timeslice level, making use of the steering class CbmReco. ** Currently included stages: @@ -36,7 +37,8 @@ using std::string; ** the extension .tsa by .digi.root **/ -void reco_steer(TString tsaFile = "", TString outFile = "", int32_t numTs = std::numeric_limits<int32_t>::max()) +void reco_steer(TString tsaFile = "", TString outFile = "", int32_t numTs = std::numeric_limits<int32_t>::max(), + uint32_t port = 8080) { // ======================================================================== @@ -98,7 +100,7 @@ void reco_steer(TString tsaFile = "", TString outFile = "", int32_t numTs = std: // ----- Run reconstruction ------------------------------------------- TStopwatch timer; timer.Start(); - CbmReco run(inFile.Data(), outFile.Data(), numTs, config); + CbmReco run(inFile.Data(), outFile.Data(), numTs, config, port); run.Run(); timer.Stop(); // ------------------------------------------------------------------------ diff --git a/macro/reco/reco_ts.C b/macro/reco/reco_ts.C index e520b169d94ecab63c2005abbd702c95d689118a..ea0cebc743deb64122323809161f4842fb639518 100644 --- a/macro/reco/reco_ts.C +++ b/macro/reco/reco_ts.C @@ -65,6 +65,7 @@ void reco_ts(TString tsaFile = "", TString outFile = "") // TODO: Would need a small up-to-date default input file; the one distributed with // the code is outdated. + // ----- Default file names --------------------------------------------- if (tsaFile.IsNull()) tsaFile = srcDir + "/input/mcbm_run399_first20Ts"; TString inFile = tsaFile + ".tsa"; @@ -121,6 +122,13 @@ void reco_ts(TString tsaFile = "", TString outFile = "") // ------------------------------------------------------------------------ + // ----- Event QA ----------------------------------------------------- + auto eventQa = std::make_unique<CbmTaskDigiEventQa>(); + LOG(info) << myName << ": Added task " << eventQa->GetName(); + run->AddTask(eventQa.release()); + // ------------------------------------------------------------------------ + + // ----- Logger settings ---------------------------------------------- FairLogger::GetLogger()->SetLogScreenLevel(logLevel.Data()); FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosity.Data()); diff --git a/reco/tasks/CMakeLists.txt b/reco/tasks/CMakeLists.txt index dd87b3a51de4bf5eee4813a1e30b2dc18cd07808..7d98de2467e7d82c137bfb90a86f20ceb3bf3e22 100644 --- a/reco/tasks/CMakeLists.txt +++ b/reco/tasks/CMakeLists.txt @@ -13,6 +13,7 @@ set(SRCS CbmReco.cxx CbmSourceTs.cxx CbmTaskBuildEvents.cxx +CbmTaskDigiEventQa.cxx CbmTaskMakeRecoEvents.cxx CbmTaskTriggerDigi.cxx CbmTaskUnpack.cxx diff --git a/reco/tasks/CbmReco.cxx b/reco/tasks/CbmReco.cxx index ccfd00a3167782bea1354549e17e8d5f2de8b7db..373191c2b9e1233e406d4ddb8c95e7667775be81 100644 --- a/reco/tasks/CbmReco.cxx +++ b/reco/tasks/CbmReco.cxx @@ -6,6 +6,7 @@ #include "CbmSourceTs.h" #include "CbmTaskBuildEvents.h" +#include "CbmTaskDigiEventQa.h" #include "CbmTaskTriggerDigi.h" #include "CbmTaskUnpack.h" #include "CbmTsEventHeader.h" @@ -14,6 +15,9 @@ #include <FairRootFileSink.h> #include <FairRunOnline.h> +#include <THttpServer.h> +#include <TRootSniffer.h> + #include <iostream> #include <memory> #include <string> @@ -25,22 +29,25 @@ using std::string; // ----- Constructor from single source ----------------------------------- -CbmReco::CbmReco(string source, TString outFile, int32_t numTs, const CbmRecoConfig& config) +CbmReco::CbmReco(string source, TString outFile, int32_t numTs, const CbmRecoConfig& config, uint16_t port) : fSourceNames {source} , fOutputFileName(outFile) , fNumTs(numTs) , fConfig(config) + , fHttpServerPort(port) { } // ---------------------------------------------------------------------------- // ----- Constructor from multiple sources -------------------------------- -CbmReco::CbmReco(std::vector<string> sources, TString outFile, int32_t numTs, const CbmRecoConfig& config) +CbmReco::CbmReco(std::vector<string> sources, TString outFile, int32_t numTs, const CbmRecoConfig& config, + uint16_t port) : fSourceNames(sources) , fOutputFileName(outFile) , fNumTs(numTs) , fConfig(config) + , fHttpServerPort(port) { } // ---------------------------------------------------------------------------- @@ -102,6 +109,10 @@ int32_t CbmReco::Run() evtBuild->SetEventWindow(entry.first, entry.second.first, entry.second.second); evtBuild->SetOutputBranchPersistent("DigiEvent", fConfig.fStoreEvents); + // --- Event QA + auto evtQa = make_unique<CbmTaskDigiEventQa>(); + evtQa->Config(fConfig); + // --- Run configuration FairRunOnline run(source.release()); run.SetSink(sink.release()); @@ -109,6 +120,14 @@ int32_t CbmReco::Run() run.AddTask(unpack.release()); run.AddTask(trigger.release()); run.AddTask(evtBuild.release()); + run.AddTask(evtQa.release()); + + // ----- HttpServer for online monitoring + if (fHttpServerPort) { + Int_t serverRefreshRate = 100; // timeslices + run.ActivateHttpServer(serverRefreshRate, fHttpServerPort); + run.GetHttpServer()->GetSniffer()->SetScanGlobalDir(kFALSE); + } // --- Initialise and start run timer.Stop(); diff --git a/reco/tasks/CbmReco.h b/reco/tasks/CbmReco.h index 32dbdb004859a5bf490afc24718b816418c000e9..28aaf291efaecd9cab7d6fef7b65fbebbe922d9e 100644 --- a/reco/tasks/CbmReco.h +++ b/reco/tasks/CbmReco.h @@ -64,8 +64,9 @@ public: ** @param outFile Name of output file ** @param numTs Number of timeslices to process. If negative, all available will be used. ** @param config Configuration + ** @param port Port number for the http server. If 0, server will not be activated. **/ - CbmReco(std::string source, TString outFile, int32_t numTs, const CbmRecoConfig& config); + CbmReco(std::string source, TString outFile, int32_t numTs, const CbmRecoConfig& config, uint16_t port = 0); /** @brief Standard constructor for list of sources @@ -73,8 +74,10 @@ public: ** @param outFile Name of output file ** @param numTs Number of timeslices to process. If negative, all available will be used. ** @param config Configuration + ** @param port Port number for the http server **/ - CbmReco(std::vector<std::string> sources, TString outFile, int32_t numTs, const CbmRecoConfig& config); + CbmReco(std::vector<std::string> sources, TString outFile, int32_t numTs, const CbmRecoConfig& config, + uint16_t port = 0); /** @brief Destructor **/ @@ -98,6 +101,7 @@ private: TString fOutputFileName = ""; ///< Output file int32_t fNumTs = 0; ///< Number of timeslices to process CbmRecoConfig fConfig = {}; ///< Configuration parameters + uint16_t fHttpServerPort = 0; ClassDef(CbmReco, 1); }; diff --git a/reco/tasks/CbmRecoTasksLinkDef.h b/reco/tasks/CbmRecoTasksLinkDef.h index 9d2dbacc5b1bc63f4f357949980a9a098d3508d1..ac0ef949083e0ac7e4329d9aca8f1a5c0ea99b88 100644 --- a/reco/tasks/CbmRecoTasksLinkDef.h +++ b/reco/tasks/CbmRecoTasksLinkDef.h @@ -15,6 +15,7 @@ #pragma link C++ class CbmRecoConfig + ; #pragma link C++ class CbmSourceTs + ; #pragma link C++ class CbmTaskBuildEvents + ; +#pragma link C++ class CbmTaskDigiEventQa + ; #pragma link C++ class CbmTaskMakeRecoEvents + ; #pragma link C++ class CbmTaskTriggerDigi + ; #pragma link C++ class CbmTaskUnpack + ; diff --git a/reco/tasks/CbmTaskDigiEventQa.cxx b/reco/tasks/CbmTaskDigiEventQa.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d45ff3c4e3cf0b5ecd2d2c6a9eb81171b91af78f --- /dev/null +++ b/reco/tasks/CbmTaskDigiEventQa.cxx @@ -0,0 +1,164 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Volker Friese [committer] */ + +#include "CbmTaskDigiEventQa.h" + +#include "CbmDigiBranchBase.h" +#include "CbmDigiManager.h" +#include "CbmDigiTimeslice.h" +#include "CbmModuleList.h" +#include "CbmReco.h" // for CbmRecoConfig + +#include <FairLogger.h> +#include <FairRunOnline.h> + +#include <TH1F.h> +#include <THttpServer.h> +#include <TStopwatch.h> + +#include <cassert> +#include <iomanip> +#include <iostream> + +using namespace std; + +// ----- Constructor ----------------------------------------------------- +CbmTaskDigiEventQa::CbmTaskDigiEventQa() : FairTask("DigiEventQa") {} +// --------------------------------------------------------------------------- + + +// ----- Destructor ------------------------------------------------------ +CbmTaskDigiEventQa::~CbmTaskDigiEventQa() {} +// --------------------------------------------------------------------------- + + +// ----- Configuration --------------------------------------------------- +void CbmTaskDigiEventQa::Config(const CbmRecoConfig& config) +{ + auto limitIt = config.fEvtbuildWindows.find(ECbmModuleId::kSts); + if (limitIt != config.fEvtbuildWindows.end()) { + double lower = limitIt->second.first - 10.; + double upper = limitIt->second.second + 10.; + fHistDigiTimeSts = new TH1F("hDigiTimeSts", "STS digi time in event", 100, lower, upper); + } +} +// --------------------------------------------------------------------------- + + +// ----- Execution ------------------------------------------------------- +void CbmTaskDigiEventQa::Exec(Option_t*) +{ + + // --- Timer and counters + TStopwatch timer; + timer.Start(); + double sumT = 0.; + double sumTsq = 0.; + double sumNumDigis = 0.; + double sumNumDigisSq = 0.; + size_t numEvents = 0; + size_t numDigis = 0; + + // --- Event loop + for (const auto& event : *fEvents) { + numEvents++; + double numDigisEvt = double(event.fData.fSts.fDigis.size()); + sumNumDigis += numDigisEvt; + sumNumDigisSq += numDigisEvt * numDigisEvt; + for (const auto& digi : event.fData.fSts.fDigis) { + numDigis++; + const double tDigi = digi.GetTime() - event.fTime; + if (fHistDigiTimeSts) fHistDigiTimeSts->Fill(tDigi); + sumT += tDigi; + sumTsq += tDigi * tDigi; + } + } + + // --- First and second moments of digi times and digi numbers + double tMean = sumT / double(numDigis); + double tSqMean = sumTsq / double(numDigis); + double tRms = sqrt(tSqMean - tMean * tMean); + double numDigisMean = sumNumDigis / double(numEvents); + double numDigisSqMean = sumNumDigisSq / double(numEvents); + double numDigisRms = sqrt(numDigisSqMean - numDigisMean * numDigisMean); + + // --- Timeslice log + timer.Stop(); + fExecTime += timer.RealTime(); + stringstream logOut; + logOut << setw(15) << left << GetName() << " ["; + logOut << fixed << setw(8) << setprecision(1) << right << timer.RealTime() * 1000. << " ms] "; + logOut << "TS " << fNumTs << ", events " << numEvents << ", digis " << numDigis << ", digis per event (" + << numDigisMean << " +- " << numDigisRms << ")" + << ", digi time (" << tMean << " +- " << tRms << ") ns"; + LOG(info) << logOut.str(); + + // --- Run statistics + fNumTs++; + fNumEvents += numEvents; + fNumDigis += numDigis; + + + // See: macro/run/run_unpack_online.C + // See : recp/detectors/sts/unpack/CbmStsUnpackMonitor +} +// ---------------------------------------------------------------------------- + + +// ----- End-of-timeslice action ------------------------------------------ +void CbmTaskDigiEventQa::Finish() +{ + std::cout << std::endl; + LOG(info) << "====================================="; + LOG(info) << GetName() << ": Run summary"; + LOG(info) << "Timeslices : " << fNumTs; + LOG(info) << "Events : " << fNumEvents; + LOG(info) << "Digis : " << fNumDigis; + LOG(info) << "Exec time : " << fixed << setprecision(2) << 1000. * fExecTime / double(fNumTs) << " ms / TS"; + if (fHistDigiTimeSts) + LOG(info) << "STS digi times : entries " << fHistDigiTimeSts->GetEntries() << ", mean " + << fHistDigiTimeSts->GetMean() << ", stddev " << fHistDigiTimeSts->GetStdDev(); + LOG(info) << "====================================="; + if (fHistDigiTimeSts) fHistDigiTimeSts->Write(); +} +// ---------------------------------------------------------------------------- + + +// ----- Initialisation --------------------------------------------------- +InitStatus CbmTaskDigiEventQa::Init() +{ + // --- Get FairRootManager instance + FairRootManager* ioman = FairRootManager::Instance(); + assert(ioman); + + std::cout << std::endl; + LOG(info) << "=================================================="; + LOG(info) << GetName() << ": Initialising..."; + + // --- Input data + fEvents = ioman->InitObjectAs<const std::vector<CbmDigiEvent>*>("DigiEvent"); + if (!fEvents) { + LOG(error) << GetName() << ": No input branch DigiEvent!"; + return kFATAL; + } + LOG(info) << "--- Found branch DigiEvent"; + + // --- Register histograms + THttpServer* server = FairRunOnline::Instance()->GetHttpServer(); + if (server) { + LOG(info) << "--- Http server present; registering histograms"; + if (fHistDigiTimeSts) server->Register("DigiEvent", fHistDigiTimeSts); + } + else + LOG(info) << "--- No Http server present"; + + LOG(info) << "=================================================="; + std::cout << std::endl; + + return kSUCCESS; +} +// ---------------------------------------------------------------------------- + + +ClassImp(CbmTaskDigiEventQa) diff --git a/reco/tasks/CbmTaskDigiEventQa.h b/reco/tasks/CbmTaskDigiEventQa.h new file mode 100644 index 0000000000000000000000000000000000000000..32452a9133ed177375ee9d1a39584bf67ebc9277 --- /dev/null +++ b/reco/tasks/CbmTaskDigiEventQa.h @@ -0,0 +1,82 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Volker Friese [committer] */ + +#ifndef CBMTASKDIGIEVENTQA_H +#define CBMTASKDIGIEVENTQA_H 1 + +#include "CbmDefs.h" +#include "CbmDigiEvent.h" + +#include <FairTask.h> + +#include <vector> + +//#include "EventBuilder.h" + +class CbmDigiManager; +class CbmRecoConfig; +class TH1F; + +/** @class CbmTaskDigiEventQa + ** @brief QA task class for digi events produced by the event builder + ** @author Volker Friese <v.friese@gsi.de> + ** @since 15.03.2022 + ** + ** Currently implemented functionality: histogram the STS digi time within each event. + ** To be expanded for other detector systems and probably more QA figures. + ** The histograms are published to the THttpServer. + **/ +class CbmTaskDigiEventQa : public FairTask { + +public: + /** @brief Constructor **/ + CbmTaskDigiEventQa(); + + + /** @brief Copy constructor (disabled) **/ + CbmTaskDigiEventQa(const CbmTaskDigiEventQa&) = delete; + + + /** @brief Destructor **/ + virtual ~CbmTaskDigiEventQa(); + + + /** @brief Configuration + ** @param config Reconstruction configuration + ** + ** Histograms are created with limits adjusted to the windows use by the event builder. + **/ + void Config(const CbmRecoConfig& config); + + + /** @brief Task execution **/ + virtual void Exec(Option_t* opt); + + + /** @brief Finish timeslice **/ + virtual void Finish(); + + + /** @brief Assignment operator (disabled) **/ + CbmTaskDigiEventQa& operator=(const CbmTaskDigiEventQa&) = delete; + + +private: // methods + /** @brief Task initialisation **/ + virtual InitStatus Init(); + + +private: // members + const std::vector<CbmDigiEvent>* fEvents = nullptr; //! Input data (events) + size_t fNumTs = 0; ///< Number of processed timeslices + size_t fNumEvents = 0; ///< Number of analysed events + size_t fNumDigis = 0; ///< Number of analysed digis + double fExecTime = 0.; ///< Execution time [s] + TH1F* fHistDigiTimeSts = nullptr; //! + + + ClassDef(CbmTaskDigiEventQa, 1); +}; + +#endif /* CBMTASKDIGIEVENTQA_H */