ATLAS Offline Software
iov_truncator.py
Go to the documentation of this file.
1 #! /usr/bin/env python
2 
3 # Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
4 
5 from __future__ import with_statement, print_function
6 from collections import namedtuple
7 
8 from .sugar import RunLumi
9 from .events import iov_yielder
10 
11 try:
12  from .db import fetch_iovs
13 except ImportError:
14  def rlumi(run, lumi):
15  return run << 32 | lumi
16 
17  def un_rlumi(x):
18  return x >> 32, x & 0xFFFFFFFF
19 
20  def fetch_iovs(*args, **kwargs):
21  """
22  A dummy fetch_iovs for testing. Returns two runs, one 100 LBs long
23  and the other 50 long.
24  """
25  T = namedtuple("EOR_VAL", "since, until RunNumber")
26 
27  return map(T._make, [(rlumi( 1, 0), rlumi(1, 100), 1),
28  (rlumi( 2, 0), rlumi(2, 50), 2),
29  (rlumi(100, 0), rlumi(100, 10), 100),
30  (rlumi(101, 0), rlumi(101, 0xFFFFFFFF), 101)])
31 
32 def fix_iov_lengths(iovs, run_lengths):
33  """
34  Truncate input iovs so that their length does not exceed the length
35  of the run.
36 
37  Also clean up records which go from (run, 0) to (run+1, 0)
38 
39  `run_lengths` should be a dictionary {run_number: lumiblock count}
40  """
41  def fix_iov(iov):
42  """
43  Given an iov, correct its since and until if necessary
44  """
45  run = iov.since.run
46 
47  if iov.since.run == iov.until.run-1 and iov.until.lumi == 0:
48  iov = iov._replace(until=RunLumi(run, 0xFFFFFFFF))
49 
50  if run in run_lengths:
51  run_length = run_lengths[run]
52  if iov.until.lumi > run_length:
53  iov = iov._replace(until=RunLumi(run, run_length))
54 
55  if iov.since >= iov.until:
56  return None
57 
58  return iov
59 
60  return [_ for _ in map(fix_iov, iovs) if _ is not None]
61 
62 def make_run_iovs(iovs):
63  # Find the minimum and maximum extent for this set of iovs
64  since = min(min(o.since for o in objects) for objects in iovs)
65  until = max(max(o.until for o in objects) for objects in iovs)
66 
67  run_iovs = fetch_iovs("EOR", since, until,
68  with_channel=False, what=[])
69 
70  from .oracle import atlas_runs_set
71  atlas_runs = atlas_runs_set()
72 
73  run_iovs = (iov for iov in run_iovs if iov.since.run in atlas_runs)
74  return run_iovs
75 
77  """
78  Given a set of iovs
79  """
80 
81  run_iovs = make_run_iovs(iovs)
82  return truncate_to_run_iovs(run_iovs, *iovs)
83 
84 def truncate_to_run_iovs(run_iovs, *iovs):
85  result_iovs = [[] for i in iovs]
86  active_states, ended_states = [set() for i in iovs], [set() for i in iovs]
87 
88  def bind_to_run(run_iov, active_states):
89  """
90  Given a run_iov and a set of active iovs, emit iovs which are bound
91  to this run.
92  """
93  for active_state in sorted(active_states):
94  iov = active_state._replace(
95  since=max(run_iov.since+1, active_state.since),
96  until=min(run_iov.until, active_state.until))
97 
98  if iov.since != iov.until:
99  # Prevent zero-length iovs from being emitted
100  yield iov
101 
102  for position, index, beginning, iov in iov_yielder(run_iovs, *iovs):
103  if index == 0:
104  # Run events
105  if beginning:
106  # Run start
107  # * Invalidate ended iovs
108  # * Clear sets of ended iovs
109  for active, ended in zip(active_states, ended_states):
110  active.difference_update(ended)
111  ended.clear()
112  else:
113  # Run end - Intersect active iovs for each channel with this run
114  # - Results are stored
115  for i, chan_active_states in enumerate(active_states):
116  result_iovs[i].extend(bind_to_run(iov, chan_active_states))
117  else:
118  # IOV events
119  index -= 1
120  # Add current iov to active states if it has just started, otherwise
121  # ended states.
122  action = active_states[index] if beginning else ended_states[index]
123  action.add(iov)
124 
125  return result_iovs
126 
128 
129  IOV = namedtuple("IOV", "since until channel state")
130  GOOD = True
131  BAD = False
132  A, B = 1, 2
133 
134  def __repr__(self):
135  """
136  A pretty convertor for (since, until)
137  """
138  args = un_rlumi(self.since) + un_rlumi(self.until) + (
139  self.channel, self.state)
140 
141  return "IOV(since=(%i, %i), until=(%i, %i), channel=%i, state=%s)" % args
142  IOV.__repr__ = __repr__
143 
144  iovs = [
145  IOV(0, 1, A, GOOD),
146  IOV(rlumi( 0, 0), rlumi(2**31, 0), A, GOOD),
147  IOV(rlumi( 0, 0), rlumi(100, 0), B, GOOD),
148  IOV(rlumi(100, 0), rlumi(2**31, 0), B, BAD),
149  IOV(rlumi(101, 0), rlumi(101, 100), A, GOOD),
150  IOV(rlumi(101, 0), rlumi(101, 0), B, BAD),
151  ]
152 
153  result = truncate_to_run_iovs(iovs)
154 
155  print(len(result))
156 
157  from pprint import pprint
158 
159  pprint(result)
160 
161 if __name__ == "__main__":
162 
max
#define max(a, b)
Definition: cfImp.cxx:41
python.iov_truncator.make_run_iovs
def make_run_iovs(iovs)
Definition: iov_truncator.py:62
python.iov_truncator.test_truncator
def test_truncator()
Definition: iov_truncator.py:127
python.events.iov_yielder
def iov_yielder(*iovs)
Definition: events.py:115
python.sugar.runlumi.RunLumi
RunLumi
Definition: runlumi.py:131
python.iov_truncator.un_rlumi
def un_rlumi(x)
Definition: iov_truncator.py:17
python.iov_truncator.truncate_to_run_iovs
def truncate_to_run_iovs(run_iovs, *iovs)
Definition: iov_truncator.py:84
python.iov_truncator.rlumi
def rlumi(run, lumi)
Definition: iov_truncator.py:14
python.oracle.atlas_runs_set
def atlas_runs_set()
Definition: oracle.py:142
DerivationFramework::TriggerMatchingUtils::sorted
std::vector< typename T::value_type > sorted(T begin, T end)
Helper function to create a sorted vector from an unsorted one.
CxxUtils::set
constexpr std::enable_if_t< is_bitmask_v< E >, E & > set(E &lhs, E rhs)
Convenience function to set bits in a class enum bitmask.
Definition: bitmask.h:232
min
#define min(a, b)
Definition: cfImp.cxx:40
python.iov_truncator.fix_iov_lengths
def fix_iov_lengths(iovs, run_lengths)
Definition: iov_truncator.py:32
python.iov_truncator.truncate_to_atlas_runs
def truncate_to_atlas_runs(*iovs)
Definition: iov_truncator.py:76
dbg::print
void print(std::FILE *stream, std::format_string< Args... > fmt, Args &&... args)
Definition: SGImplSvc.cxx:70
python.iov_truncator.fetch_iovs
def fetch_iovs(*args, **kwargs)
Definition: iov_truncator.py:20