Belle II Software  release-08-01-10
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 
15 namespace 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.