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