Project
Loading...
Searching...
No Matches
PHOSEnergyCalibDevice.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
19#include "CCDB/CcdbApi.h"
21#include "CCDB/CcdbObjectInfo.h"
23
24#include <fairmq/Device.h>
25#include <fairlogger/Logger.h>
26#include <string>
27#include <filesystem>
28
29using namespace o2::phos;
30
32{
34
35 mPtMin = ic.options().get<float>("ptminmgg");
36 mEminHGTime = ic.options().get<float>("eminhgtime");
37 mEminLGTime = ic.options().get<float>("eminlgtime");
38 mEDigMin = ic.options().get<float>("ecalibdigitmin");
39 mECluMin = ic.options().get<float>("ecalibclumin");
40
41 if (mOutputDir.compare("/dev/null")) {
42 mOutputDir = o2::utils::Str::rectifyDirectory(mOutputDir);
43 }
44 if (mMetaFileDir.compare("/dev/null")) {
45 mMetaFileDir = o2::utils::Str::rectifyDirectory(mMetaFileDir);
46 }
47
48 LOG(info) << "Energy calibration options";
49 LOG(info) << " output-dif=" << mOutputDir;
50 bool toFillDigits = mOutputDir.compare("/dev/null");
51 if (toFillDigits) {
52 LOG(info) << " Digits tree will be created";
53 } else {
54 LOG(info) << " Digits tree will NOT be created";
55 }
56 LOG(info) << " meta-output-dir=" << mMetaFileDir;
57 LOG(info) << " mgg histo ptMin=" << mPtMin;
58 LOG(info) << " Emin for HG time=" << mEminHGTime;
59 LOG(info) << " Emin for LG time=" << mEminLGTime;
60 LOG(info) << " Emin for out digits=" << mEDigMin;
61 LOG(info) << " Cluster Emin for out digits=" << mECluMin;
62
63 LOG(info) << " Root output dir=" << mOutputDir;
64
65 mCalibrator = std::make_unique<PHOSEnergyCalibrator>();
66
67 // read calibration and bad map objects and send them to calibrator
68 if (!mHasCalib && !mUseCCDB) {
69 mCalibParams = std::make_unique<CalibParams>(1); // Create test calibration coefficients
70 mCalibrator->setCalibration(mCalibParams.get());
71 mBadMap = std::make_unique<BadChannelsMap>(); // Create empty bad map
72 mCalibrator->setBadMap(mBadMap.get());
73 LOG(info) << "No reading BadMap/Calibration from ccdb requested, set default";
74 mHasCalib = true;
75 }
76 mCalibrator->setCuts(mPtMin, mEminHGTime, mEminLGTime, mEminHGTime, mEminLGTime);
77 mCalibrator->setFillDigitsTree(toFillDigits);
78 mCalibrator->setUpdateAtTheEndOfRunOnly();
79
80 // Create geometry instance (inclusing reading mis-alignement)
81 // instance will be pick up by Calibrator
83}
84
85//___________________________________________________________________
87{
88 static bool initOnceDone = false;
89 if (!initOnceDone) {
90 initOnceDone = true;
91 mDataTakingContext = pc.services().get<DataTakingContext>();
92 }
94}
95
97{
99
100 // Do not use ccdb if already created
101 if (!mHasCalib) { // Default map and calibration was not set, use CCDB
102 LOG(info) << "Getting calib from CCDB";
103 // update BadMap and calibration if necessary
104 auto badMapPtr = pc.inputs().get<o2::phos::BadChannelsMap*>("bdmap");
105 mCalibrator->setBadMap(badMapPtr.get());
106
107 auto calibPtr = pc.inputs().get<o2::phos::CalibParams*>("clb");
108 mCalibrator->setCalibration(calibPtr.get());
109 mHasCalib = true;
110 }
111 mOutputDigits.clear();
112
113 auto tfcounter = o2::header::get<o2::framework::DataProcessingHeader*>(pc.inputs().get("clusters").header)->startTime; // is this the timestamp of the current TF?
114 const gsl::span<const Cluster>& clusters = pc.inputs().get<gsl::span<Cluster>>("clusters");
115 const gsl::span<const CluElement>& cluelements = pc.inputs().get<gsl::span<CluElement>>("cluelements");
116 const gsl::span<const TriggerRecord>& cluTR = pc.inputs().get<gsl::span<TriggerRecord>>("clusterTriggerRecords");
117
118 LOG(debug) << "[PHOSEnergyCalibDevice - run] Received " << cluTR.size() << " TRs and " << clusters.size() << " clusters, running calibration";
119 if (mRunStartTime == 0) {
120 const auto& tinfo = pc.services().get<o2::framework::TimingInfo>();
121 mRunStartTime = tinfo.creation; // approximate time in ms
122 mRunNumber = tinfo.runNumber;
123
124 auto LHCPeriodStr = pc.services().get<RawDeviceService>().device()->fConfig->GetProperty<std::string>("LHCPeriod", "");
125 if (!(LHCPeriodStr.empty())) {
126 mLHCPeriod = LHCPeriodStr;
127 } else {
128 const char* months[12] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
129 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
130 std::time_t tt = mRunStartTime / 1000; // ms->s
131 std::tm* ltm = std::gmtime(&tt);
132 mLHCPeriod = (std::string)months[ltm->tm_mon];
133 LOG(warning) << "LHCPeriod is not available, using current month " << mLHCPeriod;
134 }
135 }
136 mCalibrator->process(tfcounter, clusters, cluelements, cluTR, mOutputDigits);
137
139}
140
142{
143 mCalibrator->checkSlotsToFinalize(o2::calibration::INFINITE_TF);
144 mCalibrator->endOfStream();
145 writeOutFile();
146}
147
149{
150 // DDS stop method: simply write the latest tree
151 LOG(info) << "STOP: writing output digits file";
152 writeOutFile();
153}
155{
156
157 if (mOutputDigits.size() < 2) { // nothing to fill, need at least 2 cluster per event
158 return;
159 }
160
161 LOG(info) << "Filling tree with " << mOutputDigits.size() << " digits";
162 if (!mFileOut) { // create file and tree
163 if (mWriteRootOutput) {
164 mFileName = mOutputDir + fmt::format("PHOS_CalibDigits_{}.root", mRunNumber);
165 LOG(info) << "Creating new tree for PHOS calib digits, output file=" << mFileName;
166 mFileOut = std::make_unique<TFile>(mFileName.c_str(), "recreate");
167 mFileMetaData = std::make_unique<o2::dataformats::FileMetaData>();
168 mHistoFileName = mOutputDir + fmt::format("PHOS_CalibHistos_{}.root", mRunNumber);
169 mHistoFileOut = std::make_unique<TFile>(mHistoFileName.c_str(), "recreate");
170 mHistoFileMetaData = std::make_unique<o2::dataformats::FileMetaData>();
171 mFileOut->cd();
172 }
173 // else Tree will be memory resident
174 if (!mTreeOut) {
175 LOG(info) << "Creating new tree for PHOS calib digits";
176 mTreeOut = std::make_unique<TTree>("phosCalibDig", "O2 PHOS calib tree");
177 }
178 }
179 auto* br = mTreeOut->GetBranch("PHOSCalib");
180 if (!br) {
181 br = mTreeOut->Branch("PHOSCalib", &mOutputDigits);
182 }
183 mTreeOut->Fill();
184}
185
187{
188 if (!mWriteRootOutput) {
189 return;
190 }
191 // write collected vector and metadata
192 if (!mTreeOut) { // nothing to write,
193 return;
194 }
195 LOG(info) << "Writing calibration digits";
196
197 int nbits = mTreeOut->Write();
198 LOG(info) << "Wrote " << nbits << " bits";
199 mTreeOut.reset();
200 mFileOut->Close();
201 mFileOut.reset();
202
203 // write metaFile data
204 mFileMetaData->fillFileData(mFileName);
205 mFileMetaData->setDataTakingContext(mDataTakingContext);
206 mFileMetaData->type = "calib";
207 mFileMetaData->priority = "high";
208
209 std::string metaFileNameTmp = mMetaFileDir + fmt::format("PHOS_CalibDigits_{}.tmp", mRunNumber);
210 std::string metaFileName = mMetaFileDir + fmt::format("PHOS_CalibDigits_{}.done", mRunNumber);
211 if (mMetaFileDir.compare("/dev/null")) {
212 try {
213 std::ofstream metaFileOut(metaFileNameTmp);
214 metaFileOut << *mFileMetaData.get();
215 metaFileOut.close();
216 std::filesystem::rename(metaFileNameTmp, metaFileName);
217 } catch (std::exception const& e) {
218 LOG(error) << "Failed to store PHOS meta data file " << metaFileName << ", reason: " << e.what();
219 }
220 LOG(info) << "Stored metadate file " << mFileName << ".done";
221 } else {
222 LOG(info) << "Scipped storing metafile as meta-dir=" << mMetaFileDir;
223 }
224 mFileMetaData.reset();
225
226 LOG(info) << "Writing calibration histograms";
227 mHistoFileOut->cd();
228 mHistoFileOut->WriteObjectAny(mCalibrator->getCollectedHistos(), "o2::phos::ETCalibHistos", "histos");
229 mHistoFileOut->Close();
230 mHistoFileOut.reset();
231
232 // write metaFile data
233 mHistoFileMetaData->fillFileData(mHistoFileName);
234 mHistoFileMetaData->setDataTakingContext(mDataTakingContext);
235 mHistoFileMetaData->type = "calib";
236 mHistoFileMetaData->priority = "high";
237
238 metaFileNameTmp = mMetaFileDir + fmt::format("PHOS_CalibHistos_{}.tmp", mRunNumber);
239 metaFileName = mMetaFileDir + fmt::format("PHOS_CalibHistos_{}.done", mRunNumber);
240 if (mMetaFileDir.compare("/dev/null")) {
241 try {
242 std::ofstream metaFileOut(metaFileNameTmp);
243 metaFileOut << *mHistoFileMetaData.get();
244 metaFileOut.close();
245 std::filesystem::rename(metaFileNameTmp, metaFileName);
246 } catch (std::exception const& e) {
247 LOG(error) << "Failed to store PHOS histos meta data file " << metaFileName << ", reason: " << e.what();
248 }
249 LOG(info) << "Stored histos metadate file " << mHistoFileName << ".done";
250 }
251 mHistoFileMetaData.reset();
252}
253o2::framework::DataProcessorSpec o2::phos::getPHOSEnergyCalibDeviceSpec(bool useCCDB, const std::string& outputDir, const std::string& metaFileDir, bool writeRootOutput)
254{
255
256 std::vector<InputSpec> inputs;
257 inputs.emplace_back("clusters", o2::header::gDataOriginPHS, "CLUSTERS", 0, o2::framework::Lifetime::Timeframe);
258 inputs.emplace_back("cluelements", o2::header::gDataOriginPHS, "CLUELEMENTS", 0, o2::framework::Lifetime::Timeframe);
259 inputs.emplace_back("clusterTriggerRecords", o2::header::gDataOriginPHS, "CLUSTERTRIGREC", 0, o2::framework::Lifetime::Timeframe);
260 if (useCCDB) {
261 inputs.emplace_back("bdmap", o2::header::gDataOriginPHS, "PHS_BM", 0, o2::framework::Lifetime::Condition, o2::framework::ccdbParamSpec("PHS/Calib/BadMap"));
262 inputs.emplace_back("clb", o2::header::gDataOriginPHS, "PHS_Calibr", 0, o2::framework::Lifetime::Condition, o2::framework::ccdbParamSpec("PHS/Calib/CalibParams"));
263 }
264 auto ccdbRequest = std::make_shared<o2::base::GRPGeomRequest>(true, // orbitResetTime
265 true, // GRPECS=true
266 false, // GRPLHCIF
267 false, // GRPMagField
268 false, // askMatLUT
270 inputs);
272 std::vector<OutputSpec> outputs;
273
274 return o2::framework::DataProcessorSpec{"PHOSEnergyCalibDevice",
275 inputs,
276 outputs,
277 o2::framework::adaptFromTask<PHOSEnergyCalibDevice>(useCCDB, ccdbRequest, outputDir, metaFileDir, writeRootOutput),
279 {"ptminmgg", o2::framework::VariantType::Float, 1.5f, {"minimal pt to fill mgg calib histos"}},
280 {"eminhgtime", o2::framework::VariantType::Float, 1.5f, {"minimal E (GeV) to fill HG time calib histos"}},
281 {"eminlgtime", o2::framework::VariantType::Float, 5.f, {"minimal E (GeV) to fill LG time calib histos"}},
282 {"ecalibdigitmin", o2::framework::VariantType::Float, 0.05f, {"minimal digtit E (GeV) to keep digit for calibration"}},
283 {"ecalibclumin", o2::framework::VariantType::Float, 0.4f, {"minimal cluster E (GeV) to keep digit for calibration"}}}};
284}
Utils and constants for calibration and related workflows.
Device to collect histos and digits for PHOS energy and time calibration.
std::ostringstream debug
void checkUpdates(o2::framework::ProcessingContext &pc)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
ConfigParamRegistry const & options()
Definition InitContext.h:33
decltype(auto) get(R binding, int part=0) const
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
CCDB container for bad (masked) channels in PHOS.
static Geometry * GetInstance()
Definition Geometry.h:63
void updateTimeDependentParams(ProcessingContext &pc)
void endOfStream(o2::framework::EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
void init(o2::framework::InitContext &ic) final
void run(o2::framework::ProcessingContext &pc) final
void stop() final
This is invoked on stop.
constexpr o2::header::DataOrigin gDataOriginPHS
Definition DataHeader.h:574
constexpr TFType INFINITE_TF
Definition TimeSlot.h:30
std::vector< ConfigParamSpec > ccdbParamSpec(std::string const &path, int runDependent, std::vector< CCDBMetadata > metadata={}, int qrate=0)
std::vector< ConfigParamSpec > Options
o2::framework::DataProcessorSpec getPHOSEnergyCalibDeviceSpec(bool useCCDB, const std::string &outputDir, const std::string &metaFileDir, bool writeRootOutput)
static std::string rectifyDirectory(const std::string_view p)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Cluster > clusters