Belle II Software development
GlobalTimeLine.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <alignment/GlobalTimeLine.h>
10
11#include <alignment/Manager.h>
12#include <framework/core/PyObjConvUtils.h>
13#include <framework/database/EventDependency.h>
14
15namespace Belle2 {
20 namespace alignment {
21 namespace timeline {
22
23 EventMetaData gotoNextChangeRunWise(TimeTable& timeTable, int uid, int& timeid)
24 {
25 auto& row = std::get<TableData>(timeTable).at(uid);
26
27 auto lastIntervalStartEvent = std::get<EventHeader>(timeTable).at(row.size() - 1);
28
29 if (timeid >= int(row.size())) {
30 return lastIntervalStartEvent;
31 }
32
33 auto cell = row.at(timeid);
34 auto cellRun = std::get<RunHeader>(timeTable).at(timeid);
35 for (long unsigned int iCol = timeid + 1; iCol < row.size(); ++iCol) {
36 if (row.at(iCol) != cell && std::get<RunHeader>(timeTable).at(iCol) != cellRun) {
37 timeid = iCol - 1;
38 return std::get<EventHeader>(timeTable).at(iCol);
39 //return std::get<EventHeader>(timeTable).at(iCol - 1);
40 }
41 }
42 timeid = row.size() - 1;
43
44 return lastIntervalStartEvent;
45 }
46
47 EventMetaData gotoNextChangeInRun(TimeTable& timeTable, int uid, int& timeid)
48 {
49 auto& row = std::get<TableData>(timeTable).at(uid);
50 auto cell = row.at(timeid);
51 auto cellRun = std::get<RunHeader>(timeTable).at(timeid);
52 for (long unsigned int iCol = timeid + 1; iCol < row.size(); ++iCol) {
53 if (std::get<RunHeader>(timeTable).at(iCol) != cellRun) {
54 timeid = iCol - 1;
55 return std::get<EventHeader>(timeTable).at(iCol - 1);
56 }
57 if (row.at(iCol) != cell) {
58 timeid = iCol;
59 return std::get<EventHeader>(timeTable).at(iCol);
60 }
61 }
62 return std::get<EventHeader>(timeTable).at(timeid);
63 }
64
65 PayloadsTable TimeIdsTable2PayloadsTable(TimeTable& timeTable, const GlobalParamVector& vector)
66 {
67 PayloadsTable payloadsTable;
68
69 for (auto& uid_obj : vector.getGlobalParamSets()) {
70 auto uid = uid_obj.first;
71 auto& obj = uid_obj.second;
72
73 payloadsTable[uid] = {};
74
75 if (std::get<TableData>(timeTable).find(uid) == std::get<TableData>(timeTable).end()) {
76 auto firstEvent = std::get<EventHeader>(timeTable).at(0);
77// auto lastEvent = std::get<EventHeader>(timeTable).at(std::get<EventHeader>(timeTable).size() - 1);
78
79 auto iov = IntervalOfValidity(firstEvent.getExperiment(), firstEvent.getRun(), -1, -1);
80 auto objCopy = std::shared_ptr<GlobalParamSetAccess>(obj->clone());
81 payloadsTable[uid].push_back({ iov, {{firstEvent, objCopy}} });
82
83 continue;
84 }
85 int iCol = 0;
86 // Now add PayloadIovBlockRow with run-spanning IoVs
87 for (; iCol < int(std::get<EventHeader>(timeTable).size()); ++iCol) {
88 auto event = std::get<EventHeader>(timeTable).at(iCol);
89 auto exprun = std::get<RunHeader>(timeTable).at(iCol);
90 auto exp = exprun.first;
91 auto run = exprun.second;
92
93 // Prepare intra run objects
94 // 1st is always there (even for non-intra-run)
95 auto objCopy = std::shared_ptr<GlobalParamSetAccess>(obj->clone());
96 IntraIoVPayloads intraRunEntries;
97 intraRunEntries.push_back({event, objCopy});
98 // At each change in run, add new entry
99 auto lastEvent = event;
100 for (; iCol < int(std::get<EventHeader>(timeTable).size());) {
101 auto nextEvent = gotoNextChangeInRun(timeTable, uid, iCol);
102 if (nextEvent != lastEvent) {
103 auto objIntraRunCopy = std::shared_ptr<GlobalParamSetAccess>(obj->clone());
104 intraRunEntries.push_back({nextEvent, objIntraRunCopy});
105 lastEvent = nextEvent;
106 } else {
107 break;
108 }
109 }
110
111 // Move to next IoV block (for intra-run deps in just processed block, next block is always the next run)
112 auto endEvent = gotoNextChangeRunWise(timeTable, uid, iCol);
113 int endExp = endEvent.getExperiment();
114 //int endRun = endEvent.getRun();
115 int endRun = std::max(0, endEvent.getRun() - 1);
116 // Last IoV open:
117 if (iCol == static_cast<int>(std::get<EventHeader>(timeTable).size()) - 1) {
118 endRun = -1;
119 endExp = -1;
120 }
121 // Store finished block
122 payloadsTable[uid].push_back({IntervalOfValidity(exp, run, endExp, endRun), intraRunEntries});
123
124 }
125
126 }
127
128 return payloadsTable;
129 }
130
131 TimeTable makeInitialTimeTable(std::vector< EventMetaData > events, GlobalLabel& label)
132 {
133 TimeTable table;
134 std::vector<int> nullRow(events.size(), 0);
135
136 // event header
137 std::get<EventHeader>(table) = events;
138
139 // run header
140 RunHeader runs;
141 for (auto event : events) {
142 runs.push_back({event.getExperiment(), event.getRun()});
143 }
144 std::get<RunHeader>(table) = runs;
145
146 for (auto& eidpid_intervals : label.getTimeIntervals()) {
147 auto uid = GlobalLabel(eidpid_intervals.first).getUniqueId();
148 if (std::get<TableData>(table).find(uid) == std::get<TableData>(table).end()) {
149 std::get<TableData>(table)[uid] = nullRow;
150 }
151 unsigned int lastTime = 0;
152 for (long unsigned int timeid = 0; timeid < events.size(); ++timeid) {
153 if (lastTime != eidpid_intervals.second.get(timeid)) {
154 std::get<TableData>(table)[uid][timeid] = 1;
155 lastTime = timeid;
156 }
157 }
158 }
159
160 return table;
161 }
162
163 void finalizeTimeTable(TimeTable& table)
164 {
165 for (auto& row : std::get<TableData>(table)) {
166 auto& cells = row.second;
167
168 int currIndex = 0;
169 for (long unsigned int iCell = 0; iCell < cells.size(); ++iCell) {
170 auto cell = cells.at(iCell);
171 if (iCell == 0) {
172 if (cell != 0) {
173 B2FATAL("First cell (index 0) has to be zero (time id for const objects or 1st instance of time-dep objects) for each row.");
174 }
175 continue;
176 }
177 if (cell != 0 && cell != 1) {
178 B2FATAL("In initial time table, only cells with 0 (=no change of object at beginning of cell) or 1 (object can change at beginning of this cell) are allowed");
179 }
180 // Now cell is not first and is either 0 or 1 (-> increment index)
181 if (cell == 1) {
182 ++currIndex;
183 }
184 cells.at(iCell) = currIndex;
185 }
186 }
187 }
188
189 std::pair< EventMetaData, std::shared_ptr< GlobalParamSetAccess > > getPayloadByContinuousIndex(PayloadsTable& payloadsTable,
190 int uid, long unsigned int index)
191 {
192 auto& row = payloadsTable.at(uid);
193
194 long unsigned int currentIndex = 0;
195 for (long unsigned int iIovBlock = 0; iIovBlock < row.size(); ++iIovBlock) {
196 if (currentIndex + row.at(iIovBlock).second.size() > index) {
197 return row.at(iIovBlock).second.at(index - currentIndex);
198 }
199 currentIndex += row.at(iIovBlock).second.size();
200 }
201
202 return {EventMetaData(), {}};
203 }
204
205 int getContinuousIndexByTimeID(const TimeTable& timeTable, int uid, int timeid)
206 {
207 if (timeid <= 0)
208 return 0;
209 if (std::get<TableData>(timeTable).find(uid) == std::get<TableData>(timeTable).end())
210 return 0;
211 if (timeid >= int(std::get<TableData>(timeTable).at(uid).size()))
212 return std::get<TableData>(timeTable).at(uid).size() - 1;
213
214 auto cIndex = std::get<TableData>(timeTable).at(uid)[timeid];
215 return cIndex;
216 }
217
218 // GlobalParamTimeLine class -------------------------------------------------------------------------------------
219
220 GlobalParamTimeLine::GlobalParamTimeLine(const std::vector< EventMetaData >& events, GlobalLabel& label,
221 const GlobalParamVector& vector) : timeTable(makeInitialTimeTable(events, label))
222 {
223 finalizeTimeTable(timeTable);
224 payloadsTable = TimeIdsTable2PayloadsTable(timeTable, vector);
225
226 }
227
229 {
230 std::map<std::tuple<int, int, int>, std::vector<std::shared_ptr<GlobalParamSetAccess>>> eventPayloads{};
231 for (auto& row : payloadsTable) {
232 for (auto& iovBlock : row.second) {
233 for (auto& payload : iovBlock.second) {
234 auto eventTuple = std::make_tuple((int)payload.first.getExperiment(), (int)payload.first.getRun(), (int)payload.first.getEvent());
235 auto iter_and_inserted = eventPayloads.insert(
236 {eventTuple, std::vector<std::shared_ptr<GlobalParamSetAccess>>()}
237 );
238 iter_and_inserted.first->second.push_back(payload.second);
239 }
240 }
241 }
242 for (auto event_payloads : eventPayloads) {
243 auto event = EventMetaData(std::get<2>(event_payloads.first), std::get<1>(event_payloads.first), std::get<0>(event_payloads.first));
244 DBStore::Instance().update(event);
245 DBStore::Instance().updateEvent(event.getEvent());
246 for (auto& payload : event_payloads.second) {
247 payload->loadFromDBObjPtr();
248 }
249 }
250 }
251
252 void GlobalParamTimeLine::updateGlobalParam(GlobalLabel label, double correction, bool resetParam)
253 {
254 auto timeid = label.getTimeId();
255 auto eov = label.getEndOfValidity();
256 auto uid = label.getUniqueId();
257
258 std::set<int> payloadIndices;
259 // this is probably dangerous if we do not impose additional invariant
260 //TODO: better to always loop over whole event header?
261 for (int i = timeid; i < std::min(eov + 1, int(std::get<EventHeader>(timeTable).size())); ++i) {
262 payloadIndices.insert(getContinuousIndexByTimeID(timeTable, uid, i));
263 }
264
265 for (auto payloadIndex : payloadIndices) {
266 auto payload = getPayloadByContinuousIndex(payloadsTable, label.getUniqueId(), payloadIndex).second;
267 // If not found, we get an empty payload shared ptr
268 if (payload) {
269 if (resetParam) {
270 payload->setGlobalParam(correction, label.getElementId(), label.getParameterId());
271 } else {
272 payload->updateGlobalParam(correction, label.getElementId(), label.getParameterId());
273 }
274 }
275 }
276
277 }
278
279 std::vector< std::pair< IntervalOfValidity, TObject* > > GlobalParamTimeLine::releaseObjects()
280 {
281 std::vector<std::pair<IntervalOfValidity, TObject*>> result;
282
283 for (auto& row : payloadsTable) {
284 for (auto& iovBlock : row.second) {
285 auto iov = iovBlock.first;
286 auto obj = iovBlock.second.at(0).second->releaseObject();
287
288 // non-intra-run
289 if (iovBlock.second.size() == 1) {
290 if (obj)
291 result.push_back({iov, obj});
292
293 continue;
294 }
295
296 // First obj in event dependency
297 //TODO: how the lifetime of EventDependency is handled?
298 // both work now -> have to check data storage in DB in real life scenario
299 auto payloads = new EventDependency(obj);
300 //auto payloads = EventDependency(obj);
301 // Add others
302 for (long unsigned int iObj = 1; iObj < iovBlock.second.size(); ++iObj) {
303 auto nextEvent = iovBlock.second.at(iObj).first.getEvent();
304 auto nextObj = iovBlock.second.at(iObj).second->releaseObject();
305
306 if (nextObj)
307 payloads->add(nextEvent, nextObj);
308 //payloads.add(nextEvent, nextObj);
309 }
310 result.push_back({iov, payloads});
311 //result.push_back({iov, &payloads});
312 }
313 }
314 return result;
315 }
316
317 std::vector< EventMetaData > setupTimedepGlobalLabels(PyObject* config)
318 {
319 boost::python::handle<> handle(boost::python::borrowed(config));
320 boost::python::list configList(handle);
321 auto newConfig = PyObjConvUtils::convertPythonObject(configList,
322 std::vector< std::tuple< std::vector< int >, std::vector< std::tuple< int, int, int > > > >());
323 return setupTimedepGlobalLabels(newConfig);
324
325 }
326
327
328 std::vector<EventMetaData> setupTimedepGlobalLabels(
329 std::vector< std::tuple< std::vector< int >, std::vector< std::tuple< int, int, int > > > >& config)
330 {
331 std::vector< std::tuple< std::set< int >, std::set< std::tuple< int, int, int > > > > myConfig = {};
332 std::set<std::tuple<int, int, int>> events;
333 for (auto& params_events : config) {
334 auto myRow = std::make_tuple(std::set<int>(), std::set<std::tuple< int, int, int>>());
335
336 for (auto& param : std::get<0>(params_events))
337 std::get<0>(myRow).insert(param);
338 for (auto& event : std::get<1>(params_events)) {
339 // WARNING: The function expect event metadata tuple in form (event, run, exp) while the implementation internally
340 // reverses this for proper sorting of event metadata in sets!
341 std::get<1>(myRow).insert(std::make_tuple(std::get<2>(event), std::get<1>(event), std::get<0>(event)));
342 }
343
344 for (auto& event : std::get<1>(params_events)) {
345 int eventNum = std::get<0>(event);
346 int runNum = std::get<1>(event);
347 int expNum = std::get<2>(event);
348
349 // WARNING: here we also need reversed order for the set to be sorted in ascending order
350 auto emd = std::make_tuple(expNum, runNum, eventNum);
351 events.insert(emd);
352
353
354 if (eventNum != 0) {
355 // Automatically add start of this run and start of next run as points where params can change
356 //NOTE: this is the main invariant we need to keep - if something can change inside run, it is expected
357 // it did change since last run and will change for next run, too... (i.e. if there is an event depencency,
358 // the IoV of the payload has to span only single run)
359 auto firstEventThisRun = std::make_tuple(expNum, runNum, 0);
360 auto firstEventNextRun = std::make_tuple(expNum, runNum + 1, 0);
361
362 events.insert(firstEventThisRun);
363 events.insert(firstEventNextRun);
364
365 std::get<1>(myRow).insert(firstEventThisRun);
366 std::get<1>(myRow).insert(firstEventNextRun);
367 }
368 }
369 myConfig.push_back(myRow);
370 }
371
372 std::vector<EventMetaData> eventsVect;
373 std::map<std::tuple<int, int, int>, int> eventIndices;
374
375
376 for (auto& event : events) {
377 // WARNING: here we reverse order of exp,run,event back to "normal"
378 eventIndices[event] = eventsVect.size();
379 eventsVect.push_back(EventMetaData(std::get<2>(event), std::get<1>(event), std::get<0>(event)));
380 }
381
383
384 for (auto& params_events : myConfig) {
385 for (auto& param : std::get<0>(params_events)) {
386 GlobalLabel label(param);
387
388 for (auto& event : std::get<1>(params_events)) {
389 auto eventIndex = eventIndices[event];
390 //if (eventIndex > 0)
391 label.registerTimeDependent(eventIndex);
392
393 }
394 }
395 }
396
397 return eventsVect;
398 }
399 }
400 }
402}
Class for handling changing conditions as a function of event number.
Store event, run, and experiment numbers.
Definition: EventMetaData.h:33
Class to convert to/from global labels for Millepede II to/from detector & parameter identificators.
Definition: GlobalLabel.h:41
static void clearTimeDependentParamaters()
Forget all previously registered time dependent parameters.
Definition: GlobalLabel.cc:66
The central user class to manipulate any global constant in any DB object Used to retrieve global par...
Definition: GlobalParam.h:327
GlobalParamTimeLine(const std::vector< EventMetaData > &events, GlobalLabel &label, const GlobalParamVector &vector)
Constructor.
PayloadsTable payloadsTable
Table with payloads.
std::vector< std::pair< IntervalOfValidity, TObject * > > releaseObjects()
Release all the objects (you become the owner!) for DB storage.
void loadFromDB()
Load every single payload with the content in database at its corresponding event (when it should sta...
void updateGlobalParam(GlobalLabel label, double correction, bool resetParam=false)
Add a correction to any payload's parameter in the timeline.
TimeTable timeTable
The final TimeTable with payload indices.
static DBStore & Instance()
Instance of a singleton DBStore.
Definition: DBStore.cc:28
void updateEvent()
Updates all intra-run dependent objects.
Definition: DBStore.cc:142
void update()
Updates all objects that are outside their interval of validity.
Definition: DBStore.cc:79
Scalar convertPythonObject(const boost::python::object &pyObject, Scalar)
Convert from Python to given type.
Abstract base class for different kinds of events.