Project
Loading...
Searching...
No Matches
SectorEdgeFluctuations.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
14
16#include "DataFormatsTPC/Defs.h"
17#include "TTree.h"
18#include "TFile.h"
19
20#include <fstream>
21#include <sstream>
22#include <stdexcept>
23#include <algorithm>
24#include <map>
25
26#include "Framework/Logger.h"
27
28namespace o2::tpc
29{
30
31int SectorEdgeFluctuations::parseSectorId(const std::string& sectorStr)
32{
33 if (sectorStr.size() < 2) {
34 return -1;
35 }
36
37 const char side = std::toupper(static_cast<unsigned char>(sectorStr[0]));
38 if (side != 'A' && side != 'C') {
39 return -1;
40 }
41
42 int num = -1;
43 try {
44 num = std::stoi(sectorStr.substr(1));
45 } catch (...) {
46 return -1;
47 }
48
49 if (num < 0 || num > 17) {
50 return -1;
51 }
52
53 return (side == 'A') ? num : (num + SECTORSPERSIDE);
54}
55
57{
58 mIntervals.clear();
59
60 std::ifstream file(filename);
61 if (!file.is_open()) {
62 LOGP(error, "SectorEdgeFluctuations: cannot open file: {}", filename);
63 return false;
64 }
65
66 std::string line;
67 int lineNum = 0;
68 int nSkipped = 0;
69 int nLoaded = 0;
70
71 while (std::getline(file, line)) {
72 ++lineNum;
73
74 // skip empty lines and comments
75 const auto firstNonSpace = line.find_first_not_of(" \t\r\n");
76 if (firstNonSpace == std::string::npos || line[firstNonSpace] == '#') {
77 continue;
78 }
79
80 // tokenise on comma
81 std::vector<std::string> tokens;
82 {
83 std::stringstream ss(line);
84 std::string tok;
85 while (std::getline(ss, tok, ',')) {
86 // trim leading/trailing whitespace
87 const auto s = tok.find_first_not_of(" \t\r\n");
88 const auto e = tok.find_last_not_of(" \t\r\n");
89 tokens.push_back((s == std::string::npos) ? "" : tok.substr(s, e - s + 1));
90 }
91 }
92
93 // minimum: runNum(0), startMS(1), endMS(2), duration(3), label(4); sectors are optional
94 if (tokens.size() < 5) {
95 LOGP(warning, "SectorEdgeFluctuations: skipping malformed line {}", lineNum);
96 ++nSkipped;
97 continue;
98 }
99
100 int run = -1;
101 try {
102 run = std::stoi(tokens[0]);
103 } catch (...) {
104 LOGP(warning, "SectorEdgeFluctuations: cannot parse run number on line {}", lineNum);
105 ++nSkipped;
106 continue;
107 }
108
109 SectorEdgeInterval interval;
110 try {
111 interval.startTimeMS = std::stoll(tokens[1]);
112 interval.endTimeMS = std::stoll(tokens[2]);
113 } catch (...) {
114 LOGP(warning, "SectorEdgeFluctuations: cannot parse timestamps on line {}", lineNum);
115 ++nSkipped;
116 continue;
117 }
118
119 if (interval.endTimeMS < interval.startTimeMS) {
120 LOGP(warning, "SectorEdgeFluctuations: end < start on line {}, skipping", lineNum);
121 ++nSkipped;
122 continue;
123 }
124
125 // tokens[4] is the human-readable label; sectors start at index 5
126 for (size_t i = 5; i < tokens.size(); ++i) {
127 std::string sectorStr = tokens[i];
128 float scale = 1.0f;
129
130 // parse optional "SectorID=scale" suffix
131 const auto eqPos = sectorStr.find('=');
132 if (eqPos != std::string::npos) {
133 try {
134 scale = std::stof(sectorStr.substr(eqPos + 1));
135 } catch (...) {
136 LOGP(warning, "SectorEdgeFluctuations: cannot parse scale in '{}' on line {}, using 1.0", tokens[i], lineNum);
137 }
138 sectorStr = sectorStr.substr(0, eqPos);
139 }
140
141 const int sectorId = parseSectorId(sectorStr);
142 if (sectorId < 0) {
143 LOGP(warning, "SectorEdgeFluctuations: unknown sector '{}' on line {}, skipping token", sectorStr, lineNum);
144 continue;
145 }
146
147 // deduplicate: last occurrence in the line wins
148 auto dup = std::find_if(interval.sectors.begin(), interval.sectors.end(), [sectorId](const std::pair<int, float>& p) { return p.first == sectorId; });
149 if (dup != interval.sectors.end()) {
150 dup->second = scale;
151 } else {
152 interval.sectors.emplace_back(sectorId, scale);
153 }
154 }
155
156 if (interval.sectors.empty()) {
157 // no sector tokens (or all invalid): apply interval to all 36 sectors
158 const int nSec = SECTORSPERSIDE * SIDES;
159 for (int s = 0; s < nSec; ++s) {
160 interval.sectors.emplace_back(s, 1.0f);
161 }
162 }
163 mIntervals[run].push_back(std::move(interval));
164 ++nLoaded;
165 }
166
167 // sort each run's intervals by start time so getSectorsAtTime can break early
168 for (auto& [run, intervals] : mIntervals) {
169 std::sort(intervals.begin(), intervals.end(), [](const SectorEdgeInterval& a, const SectorEdgeInterval& b) {
170 return a.startTimeMS < b.startTimeMS;
171 });
172 }
173
174 LOGP(info, "SectorEdgeFluctuations: loaded {} intervals for {} run(s) from '{}' ({} lines skipped)", nLoaded, mIntervals.size(), filename, nSkipped);
175 return true;
176}
177
178std::vector<std::pair<int, float>> SectorEdgeFluctuations::getSectorsAtTime(int run, Long64_t timestampMS) const
179{
180 const auto runIt = mIntervals.find(run);
181 if (runIt == mIntervals.end()) {
182 return {};
183 }
184
185 // Collect all sectors whose interval is active at timestampMS.
186 // When the same sector appears in multiple overlapping intervals, keep the
187 // scale from the interval with the latest endTimeMS (most specific).
188 // sectorBestScale: sectorId -> {scale, endTimeMS}
189 std::map<int, std::pair<float, Long64_t>> sectorBestScale;
190
191 const auto& intervals = runIt->second;
192 const auto endIt = std::upper_bound(intervals.begin(), intervals.end(), timestampMS, [](Long64_t ts, const SectorEdgeInterval& iv) { return ts < iv.startTimeMS; });
193
194 for (auto it = intervals.begin(); it != endIt; ++it) {
195 if (it->endTimeMS < timestampMS) {
196 continue;
197 }
198 for (const auto& [sector, scale] : it->sectors) {
199 auto sit = sectorBestScale.find(sector);
200 if (sit == sectorBestScale.end() || it->endTimeMS > sit->second.second) {
201 sectorBestScale[sector] = {scale, it->endTimeMS};
202 }
203 }
204 }
205
206 std::vector<std::pair<int, float>> result;
207 result.reserve(sectorBestScale.size());
208 for (const auto& [sector, scaleAndEnd] : sectorBestScale) {
209 result.emplace_back(sector, scaleAndEnd.first);
210 }
211 return result;
212}
213
214void SectorEdgeFluctuations::dumpToFile(const char* file, const char* name, const char* brName)
215{
216 TFile out(file, "RECREATE");
217 TTree tree(name, name);
218 tree.SetAutoSave(0);
219 tree.Branch(brName, this);
220 tree.Fill();
221 tree.Write();
222 out.Close();
223}
224
225void SectorEdgeFluctuations::loadFromFile(const char* inpf, const char* name, const int iEntry, const char* brName)
226{
227 TFile inp(inpf, "READ");
228 if (inp.IsZombie() || !inp.IsOpen()) {
229 LOGP(error, "SectorEdgeFluctuations: cannot open file '{}'", inpf);
230 return;
231 }
232 TTree* tree = dynamic_cast<TTree*>(inp.Get(name));
233 if (!tree) {
234 LOGP(error, "SectorEdgeFluctuations: object '{}' not found or not a TTree in '{}'", name, inpf);
235 return;
236 }
237 setFromTree(*tree, iEntry, brName);
238}
239
240void SectorEdgeFluctuations::setFromTree(TTree& tree, const int iEntry, const char* brName)
241{
242 SectorEdgeFluctuations* msecFlucTmp = this;
243 tree.SetBranchAddress(brName, &msecFlucTmp);
244 const int entries = tree.GetEntries();
245 if (entries > iEntry) {
246 tree.GetEntry(iEntry);
247 } else {
248 LOGP(error, "SectorEdgeFluctuation not found in input file");
249 }
250 tree.SetBranchAddress(brName, nullptr);
251}
252
253} // namespace o2::tpc
int32_t i
uint32_t side
Definition RawData.h:0
Class to parse and query time-dependent TPC sector edge fluctuation intervals.
double num
bool loadFromCSVFile(const std::string &filename)
std::vector< std::pair< int, float > > getSectorsAtTime(int run, Long64_t timestampMS) const
void loadFromFile(const char *inpf, const char *name="ccdb_object", const int iEntry=0, const char *brName="SectorEdgeFluctuation")
void setFromTree(TTree &tree, const int iEntry=0, const char *brName="SectorEdgeFluctuation")
set this object from input tree
static int parseSectorId(const std::string &sectorStr)
void dumpToFile(const char *file, const char *name="ccdb_object", const char *brName="SectorEdgeFluctuation")
GLuint const GLchar * name
Definition glcorearb.h:781
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
Global TPC definitions and constants.
Definition SimTraits.h:168
constexpr unsigned char SECTORSPERSIDE
Definition Defs.h:40
constexpr unsigned char SIDES
Definition Defs.h:41
std::string filename()
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))