Skip to content

Commit b78db82

Browse files
martenoleshahor02
authored andcommitted
Adapt writing of aggregated TPC residuals for EPN
- Write metafile for TPC residuals - Make output directory for residuals configurable - Add statistics information for each TF and sort residuals in time
1 parent a30333f commit b78db82

File tree

4 files changed

+106
-7
lines changed

4 files changed

+106
-7
lines changed

Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCResidualAggregatorSpec.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include "Framework/ControlService.h"
2626
#include "Framework/WorkflowSpec.h"
2727
#include "DetectorsBase/GRPGeomHelper.h"
28+
#include "Framework/RawDeviceService.h"
29+
#include <fairmq/Device.h>
2830

2931
using namespace o2::framework;
3032

@@ -48,11 +50,24 @@ class ResidualAggregatorDevice : public o2::framework::Task
4850
}
4951
auto updateInterval = ic.options().get<uint32_t>("updateInterval");
5052
auto delay = ic.options().get<uint32_t>("max-delay");
53+
54+
std::string outputDir = o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("output-dir"));
55+
std::string metaFileDir = ic.options().get<std::string>("meta-output-dir");
56+
bool storeMetaFile = false;
57+
if (metaFileDir != "/dev/null") {
58+
metaFileDir = o2::utils::Str::rectifyDirectory(metaFileDir);
59+
storeMetaFile = true;
60+
}
5161
mAggregator = std::make_unique<o2::tpc::ResidualAggregator>(minEnt);
62+
mAggregator->setOutputDir(outputDir);
63+
if (storeMetaFile) {
64+
mAggregator->setMetaFileOutputDir(metaFileDir);
65+
}
5266
// TODO mAggregator should get an option to set the binning externally (expose TrackResiduals::setBinning methods to user? as command line option?)
5367
mAggregator->setSlotLength(slotLength);
5468
mAggregator->setMaxSlotsDelay(delay);
5569
mAggregator->setCheckIntervalInfiniteSlot(updateInterval);
70+
mAggregator->initOutput();
5671
}
5772

5873
void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) final
@@ -65,6 +80,20 @@ class ResidualAggregatorDevice : public o2::framework::Task
6580
o2::base::GRPGeomHelper::instance().checkUpdates(pc);
6681
auto data = pc.inputs().get<gsl::span<o2::tpc::TrackResiduals::UnbinnedResid>>("input");
6782
o2::base::TFIDInfoHelper::fillTFIDInfo(pc, mAggregator->getCurrentTFInfo());
83+
if (!isLHCPeriodSet) {
84+
// read the LHC period information only once
85+
const std::string NAStr = "NA";
86+
auto LHCPeriodStr = pc.services().get<RawDeviceService>().device()->fConfig->GetProperty<std::string>("LHCPeriod", NAStr);
87+
if (LHCPeriodStr == NAStr) {
88+
const char* months[12] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
89+
time_t now = time(nullptr);
90+
auto ltm = gmtime(&now);
91+
LHCPeriodStr = months[ltm->tm_mon];
92+
LOG(warning) << "LHCPeriod is not available, using current month " << LHCPeriodStr;
93+
}
94+
mAggregator->setLHCPeriod(LHCPeriodStr);
95+
isLHCPeriodSet = true;
96+
}
6897
LOG(debug) << "Processing TF " << mAggregator->getCurrentTFInfo().tfCounter << " with " << data.size() << " unbinned residuals";
6998
mAggregator->process(data);
7099
}
@@ -79,6 +108,7 @@ class ResidualAggregatorDevice : public o2::framework::Task
79108
private:
80109
std::unique_ptr<o2::tpc::ResidualAggregator> mAggregator;
81110
std::shared_ptr<o2::base::GRPGeomRequest> mCCDBRequest;
111+
bool isLHCPeriodSet{false};
82112
};
83113

84114
} // namespace calibration
@@ -105,7 +135,9 @@ DataProcessorSpec getTPCResidualAggregatorSpec()
105135
{"tf-per-slot", VariantType::UInt32, 6'000u, {"number of TFs per calibration time slot (put 0 for infinite slot length)"}},
106136
{"updateInterval", VariantType::UInt32, 6'000u, {"update interval in number of TFs in case slot length is infinite"}},
107137
{"max-delay", VariantType::UInt32, 10u, {"number of slots in past to consider"}},
108-
{"min-entries", VariantType::Int, 0, {"minimum number of entries on average per voxel"}}}};
138+
{"min-entries", VariantType::Int, 0, {"minimum number of entries on average per voxel"}},
139+
{"output-dir", VariantType::String, "none", {"Output directory for residuals, must exist"}},
140+
{"meta-output-dir", VariantType::String, "/dev/null", {"Residuals metadata output directory, must exist (if not /dev/null)"}}}};
109141
}
110142

111143
} // namespace framework

Detectors/TPC/calibration/SpacePoints/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ o2_add_library(SpacePoints
1515
src/TrackInterpolation.cxx
1616
src/ResidualAggregator.cxx
1717
PUBLIC_LINK_LIBRARIES O2::DataFormatsTPC
18+
O2::CommonUtils
1819
O2::TPCBase
1920
O2::TRDBase
2021
O2::TPCReconstruction

Detectors/TPC/calibration/SpacePoints/include/SpacePoints/ResidualAggregator.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "DetectorsCalibration/TimeSlot.h"
2121
#include "DataFormatsTPC/Defs.h"
2222
#include "SpacePoints/TrackResiduals.h"
23+
#include "CommonUtils/StringUtils.h"
2324

2425
#include <vector>
2526
#include <array>
@@ -41,7 +42,7 @@ struct ResidualsContainer {
4142
ResidualsContainer& operator=(const ResidualsContainer& src) = delete;
4243
~ResidualsContainer();
4344

44-
void init(const TrackResiduals* residualsEngine);
45+
void init(const TrackResiduals* residualsEngine, std::string outputDir);
4546
void fillStatisticsBranches();
4647
uint64_t getNEntries() const { return nResidualsTotal; }
4748

@@ -54,13 +55,18 @@ struct ResidualsContainer {
5455
std::array<std::vector<TrackResiduals::LocalResid>*, SECTORSPERSIDE * SIDES> residualsPtr{};
5556
std::array<std::vector<TrackResiduals::VoxStats>, SECTORSPERSIDE * SIDES> stats{}; ///< voxel statistics sent to the aggregator
5657
std::array<std::vector<TrackResiduals::VoxStats>*, SECTORSPERSIDE * SIDES> statsPtr{};
58+
uint32_t runNumber; ///< run number (required for meta data file)
59+
std::vector<uint32_t> tfOrbits, *tfOrbitsPtr{&tfOrbits}; ///< first TF orbit
60+
std::vector<uint32_t> sumOfResiduals, *sumOfResidualsPtr{&sumOfResiduals}; ///< sum of residuals for each TF
5761

5862
std::string fileName{"o2tpc_residuals"};
5963
std::string treeNameResiduals{"resid"};
6064
std::string treeNameStats{"stats"};
65+
std::string treeNameRecords{"records"};
6166
std::unique_ptr<TFile> fileOut{nullptr};
6267
std::unique_ptr<TTree> treeOutResiduals{nullptr};
6368
std::unique_ptr<TTree> treeOutStats{nullptr};
69+
std::unique_ptr<TTree> treeOutRecords{nullptr};
6470

6571
uint64_t nResidualsTotal{0};
6672

@@ -75,13 +81,25 @@ class ResidualAggregator final : public o2::calibration::TimeSlotCalibration<Tra
7581
ResidualAggregator(size_t nMin = 1'000) : mMinEntries(nMin) { mTrackResiduals.init(); }
7682
~ResidualAggregator() final;
7783

84+
void setOutputDir(std::string dir) { mOutputDir = dir.empty() ? o2::utils::Str::rectifyDirectory("./") : dir; }
85+
void setMetaFileOutputDir(std::string dir)
86+
{
87+
mMetaOutputDir = dir;
88+
mStoreMetaData = true;
89+
}
90+
void setLHCPeriod(std::string period) { mLHCPeriod = period; }
91+
7892
bool hasEnoughData(const Slot& slot) const final;
7993
void initOutput() final;
8094
void finalizeSlot(Slot& slot) final;
8195
Slot& emplaceNewSlot(bool front, TFType tStart, TFType tEnd) final;
8296

8397
private:
8498
TrackResiduals mTrackResiduals; ///< providing the functionality for voxel binning of the residuals
99+
std::string mOutputDir{"./"}; ///< the directory where the output of residuals is stored
100+
std::string mMetaOutputDir{"none"}; ///< the directory where the meta data file is stored
101+
std::string mLHCPeriod{""}; ///< the LHC period to be put into the meta file
102+
bool mStoreMetaData{false}; ///< flag, whether meta file is supposed to be stored
85103
size_t mMinEntries; ///< the minimum number of residuals required for the map creation (per voxel)
86104

87105
ClassDefOverride(ResidualAggregator, 1);

Detectors/TPC/calibration/SpacePoints/src/ResidualAggregator.cxx

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515

1616
#include "SpacePoints/ResidualAggregator.h"
1717
#include "SpacePoints/SpacePointsCalibParam.h"
18+
#include "DetectorsCommonDataFormats/FileMetaData.h"
1819

1920
#include <filesystem>
21+
#include <numeric>
22+
#include <algorithm>
2023

2124
using namespace o2::tpc;
2225

@@ -51,20 +54,24 @@ ResidualsContainer::ResidualsContainer(ResidualsContainer&& rhs)
5154
treeOutStats = std::move(rhs.treeOutStats);
5255
for (int iSec = 0; iSec < SECTORSPERSIDE * SIDES; ++iSec) {
5356
residuals[iSec] = std::move(rhs.residuals[iSec]);
54-
residualsPtr[iSec] = std::move(rhs.residualsPtr[iSec]);
5557
stats[iSec] = std::move(rhs.stats[iSec]);
56-
statsPtr[iSec] = std::move(rhs.statsPtr[iSec]);
5758
}
59+
runNumber = rhs.runNumber;
60+
tfOrbits = std::move(rhs.tfOrbits);
61+
sumOfResiduals = std::move(rhs.sumOfResiduals);
5862
}
5963

60-
void ResidualsContainer::init(const TrackResiduals* residualsEngine)
64+
void ResidualsContainer::init(const TrackResiduals* residualsEngine, std::string outputDir)
6165
{
6266
trackResiduals = residualsEngine;
6367
fileName += std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
6468
fileName += ".root";
65-
fileOut = std::make_unique<TFile>(fileName.c_str(), "recreate");
69+
std::string fileNameTmp = outputDir + fileName;
70+
fileNameTmp += ".part"; // to prevent premature external usage of the file use temporary name
71+
fileOut = std::make_unique<TFile>(fileNameTmp.c_str(), "recreate");
6672
treeOutResiduals = std::make_unique<TTree>(treeNameResiduals.c_str(), "TPC binned residuals");
6773
treeOutStats = std::make_unique<TTree>(treeNameStats.c_str(), "Voxel statistics mean position and nEntries");
74+
treeOutRecords = std::make_unique<TTree>(treeNameRecords.c_str(), "Statistics per TF slot");
6875
for (int iSec = 0; iSec < SECTORSPERSIDE * SIDES; ++iSec) {
6976
residualsPtr[iSec] = &residuals[iSec];
7077
statsPtr[iSec] = &stats[iSec];
@@ -81,6 +88,8 @@ void ResidualsContainer::init(const TrackResiduals* residualsEngine)
8188
treeOutResiduals->Branch(Form("sec%d", iSec), &residualsPtr[iSec]);
8289
treeOutStats->Branch(Form("sec%d", iSec), &statsPtr[iSec]);
8390
}
91+
treeOutRecords->Branch("firstTForbit", &tfOrbitsPtr);
92+
treeOutRecords->Branch("sumOfResiduals", &sumOfResidualsPtr);
8493
}
8594

8695
void ResidualsContainer::fillStatisticsBranches()
@@ -89,13 +98,15 @@ void ResidualsContainer::fillStatisticsBranches()
8998
// remains empty and we keep the statistics in memory in the vectors
9099
// (since their size anyway does not change)
91100
treeOutStats->Fill();
101+
treeOutRecords->Fill();
92102
}
93103

94104
void ResidualsContainer::fill(const o2::dataformats::TFIDInfo& ti, const gsl::span<const TrackResiduals::UnbinnedResid> data)
95105
{
96106
// receives large vector of unbinned residuals and fills the sector-wise vectors
97107
// with binned residuals and statistics
98108
LOG(debug) << "Filling ResidualsContainer with vector of size " << data.size();
109+
uint32_t nResidualsInTF = 0;
99110
for (const auto& residIn : data) {
100111
int sec = residIn.sec;
101112
auto& residVecOut = residuals[sec];
@@ -117,11 +128,15 @@ void ResidualsContainer::fill(const o2::dataformats::TFIDInfo& ti, const gsl::sp
117128
stat.meanPos[TrackResiduals::VoxF] = (stat.meanPos[TrackResiduals::VoxF] * oldEntries + yPos / param::RowX[residIn.row]) * norm;
118129
stat.meanPos[TrackResiduals::VoxZ] = (stat.meanPos[TrackResiduals::VoxZ] * oldEntries + zPos / param::RowX[residIn.row]) * norm;
119130
++nResidualsTotal;
131+
++nResidualsInTF;
120132
}
121133
treeOutResiduals->Fill();
122134
for (auto& residVecOut : residuals) {
123135
residVecOut.clear();
124136
}
137+
runNumber = ti.runNumber;
138+
tfOrbits.push_back(ti.firstTForbit);
139+
sumOfResiduals.push_back(nResidualsInTF);
125140
}
126141

127142
void ResidualsContainer::merge(ResidualsContainer* prev)
@@ -158,6 +173,13 @@ void ResidualsContainer::merge(ResidualsContainer* prev)
158173
treeOutResiduals = std::move(prev->treeOutResiduals);
159174

160175
nResidualsTotal += prev->nResidualsTotal;
176+
177+
// append the current vector to the vector of the previous container and afterwards swap them,
178+
// since the vector of the previous container will be deleted
179+
prev->tfOrbits.insert(prev->tfOrbits.end(), tfOrbits.begin(), tfOrbits.end());
180+
std::swap(prev->tfOrbits, tfOrbits);
181+
prev->sumOfResiduals.insert(prev->sumOfResiduals.end(), sumOfResiduals.begin(), sumOfResiduals.end());
182+
std::swap(prev->sumOfResiduals, sumOfResiduals);
161183
}
162184

163185
void ResidualsContainer::print()
@@ -195,15 +217,41 @@ void ResidualAggregator::finalizeSlot(Slot& slot)
195217
cont->treeOutResiduals.reset();
196218
cont->treeOutStats->Write();
197219
cont->treeOutStats.reset();
220+
cont->treeOutRecords->Write();
221+
cont->treeOutRecords.reset();
198222
cont->fileOut->Close();
199223
cont->fileOut.reset();
224+
std::filesystem::rename(o2::utils::Str::concat_string(mOutputDir, cont->fileName, ".part"), mOutputDir + cont->fileName);
225+
if (mStoreMetaData) {
226+
o2::dataformats::FileMetaData fileMetaData; // object with information for meta data file
227+
fileMetaData.fillFileData(mOutputDir + cont->fileName);
228+
fileMetaData.run = cont->runNumber;
229+
fileMetaData.LHCPeriod = mLHCPeriod;
230+
fileMetaData.type = "calib";
231+
fileMetaData.priority = "high";
232+
auto metaFileNameTmp = fmt::format("{}{}.tmp", mMetaOutputDir, cont->fileName);
233+
auto metaFileName = fmt::format("{}{}.done", mMetaOutputDir, cont->fileName);
234+
try {
235+
std::ofstream metaFileOut(metaFileNameTmp);
236+
metaFileOut << fileMetaData;
237+
metaFileOut << "TFOrbits: ";
238+
for (size_t i = 0; i < cont->tfOrbits.size(); i++) {
239+
metaFileOut << fmt::format("{}{}", i ? ", " : "", cont->tfOrbits[i]);
240+
}
241+
metaFileOut << '\n';
242+
metaFileOut.close();
243+
std::filesystem::rename(metaFileNameTmp, metaFileName);
244+
} catch (std::exception const& e) {
245+
LOG(error) << "Failed to store residuals meta data file " << metaFileName << ", reason: " << e.what();
246+
}
247+
}
200248
}
201249

202250
Slot& ResidualAggregator::emplaceNewSlot(bool front, TFType tStart, TFType tEnd)
203251
{
204252
auto& cont = getSlots();
205253
auto& slot = front ? cont.emplace_front(tStart, tEnd) : cont.emplace_back(tStart, tEnd);
206254
slot.setContainer(std::make_unique<ResidualsContainer>());
207-
slot.getContainer()->init(&mTrackResiduals);
255+
slot.getContainer()->init(&mTrackResiduals, mOutputDir);
208256
return slot;
209257
}

0 commit comments

Comments
 (0)