ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/CMSSW/PhysicsTools/PythonAnalysis/python/LumiList.py
Revision: 1.1
Committed: Tue Jun 8 16:04:16 2010 UTC (14 years, 11 months ago) by ewv
Content type: text/x-python
Branch: MAIN
Log Message:
Move code from CRAB to more general location

File Contents

# User Rev Content
1 ewv 1.1 #!/usr/bin/env python
2    
3     """
4     Handle lists of lumi sections. Constuct in several different formats and filter
5     (mask) a secondary list of lumis.
6     This class can also handle ranges of events as the structure is identical
7     or could be subclassed renaming a function or two.
8     """
9    
10     __revision__ = "$Id: LumiList.py,v 1.2 2010/02/22 14:43:56 ewv Exp $"
11     __version__ = "$Revision: 1.2 $"
12    
13     import json
14    
15     class LumiList(object):
16     """
17     Deal with lists of lumis in several different forms:
18     Compact list:
19     {
20     '1': [[1, 33], [35, 35], [37, 47], [49, 75], [77, 130], [133, 136]],
21     '2':[[1,45],[50,80]]
22     }
23     where the first key is the run number, subsequent pairs are
24     ranges of lumis within that run that are desired
25     Runs and lumis:
26     {
27     '1': [1,2,3,4,6,7,8,9,10],
28     '2': [1,4,5,20]
29     }
30     where the first key is the run number and the list is a list of
31     individual lumi sections
32     Run lumi pairs:
33     [[1,1], [1,2],[1,4], [2,1], [2,5], [1,10]]
34     where each pair in the list is an individual run&lumi
35     CMSSW representation:
36     '1:1-1:33,1:35,1:37-1:47,2:1-2:45,2:50-2:80'
37     The string used by CMSSW in lumisToProcess or lumisToSkip
38     is a subset of the compactList example above
39     """
40    
41    
42     def __init__(self, filename = None, lumis = None, runsAndLumis = None):
43     """
44     Constructor takes filename (JSON), a list of run/lumi pairs,
45     or a dict with run #'s as the keys and a list of lumis as the values
46     """
47     self.compactList = {}
48     if filename:
49     self.filename = filename
50     jsonFile = open(self.filename,'r')
51     self.compactList = json.load(jsonFile)
52     elif lumis:
53     runsAndLumis = {}
54     for (run, lumi) in lumis:
55     run = str(run)
56     if not runsAndLumis.has_key(run):
57     runsAndLumis[run] = []
58     runsAndLumis[run].append(lumi)
59    
60     if runsAndLumis:
61     for run in runsAndLumis.keys():
62     runString = str(run)
63     lastLumi = -1000
64     self.compactList[runString] = []
65     lumiList = runsAndLumis[run]
66     for lumi in sorted(lumiList):
67     if lumi == lastLumi:
68     pass # Skip duplicates
69     elif lumi != lastLumi + 1: # Break in lumi sequence
70     self.compactList[runString].append([lumi, lumi])
71     else:
72     nRange = len(self.compactList[runString])
73     self.compactList[runString][nRange-1][1] = lumi
74     lastLumi = lumi
75    
76    
77     def filterLumis(self, lumiList):
78     """
79     Return a list of lumis that are in compactList.
80     lumilist is of the simple form
81     [(run1,lumi1),(run1,lumi2),(run2,lumi1)]
82     """
83     filteredList = []
84     for (run, lumi) in lumiList:
85     runsInLumi = self.compactList.get(str(run), [[0,-1]])
86     for (first, last) in runsInLumi:
87     if lumi >= first and lumi <= last:
88     filteredList.append((run, lumi))
89     break
90     return filteredList
91    
92    
93     def getCompactList(self):
94     """
95     Return the compact list representation
96     """
97     return self.compactList
98    
99    
100     def getLumis(self):
101     """
102     Return the list of pairs representation
103     """
104     theList = []
105     runs = self.compactList.keys()
106     runs.sort(key=int)
107     for run in runs:
108     lumis = self.compactList[run]
109     for lumiPair in sorted(lumis):
110     for lumi in range(lumiPair[0], lumiPair[1]+1):
111     theList.append((int(run), lumi))
112    
113     return theList
114    
115    
116     def getCMSSWString(self):
117     """
118     Turn compactList into a list of the format
119     R1:L1,R2:L2-R2:L3 which is acceptable to CMSSW LumiBlockRange variable
120     """
121    
122     parts = []
123     runs = self.compactList.keys()
124     runs.sort(key=int)
125     for run in runs:
126     lumis = self.compactList[run]
127     for lumiPair in sorted(lumis):
128     if lumiPair[0] == lumiPair[1]:
129     parts.append("%s:%s" % (run, lumiPair[0]))
130     else:
131     parts.append("%s:%s-%s:%s" %
132     (run, lumiPair[0], run, lumiPair[1]))
133    
134     output = ','.join(parts)
135     return output
136    
137    
138    
139     # Unit test code
140     '''
141     import unittest
142     from WMCore.DataStructs.LumiList import LumiList
143    
144    
145     class LumiListTest(unittest.TestCase):
146     """
147     _LumiListTest_
148    
149     """
150    
151     def testRead(self):
152     """
153     Test reading from JSON
154     """
155     exString = "1:1-1:33,1:35,1:37-1:47,2:49-2:75,2:77-2:130,2:133-2:136"
156     exDict = {'1': [[1, 33], [35, 35], [37, 47]],
157     '2': [[49, 75], [77, 130], [133, 136]]}
158    
159     jsonList = LumiList(filename = 'lumiTest.json')
160     lumiString = jsonList.getCMSSWString()
161     lumiList = jsonList.getCompactList()
162    
163     self.assertTrue(lumiString == exString)
164     self.assertTrue(lumiList == exDict)
165    
166     def testList(self):
167     """
168     Test constucting from list of pairs
169     """
170    
171     listLs1 = range(1, 34) + [35] + range(37, 48)
172     listLs2 = range(49, 76) + range(77, 131) + range(133, 137)
173     lumis = zip([1]*100, listLs1) + zip([2]*100, listLs2)
174    
175     jsonLister = LumiList(filename = 'lumiTest.json')
176     jsonString = jsonLister.getCMSSWString()
177     jsonList = jsonLister.getCompactList()
178    
179     pairLister = LumiList(lumis = lumis)
180     pairString = pairLister.getCMSSWString()
181     pairList = pairLister.getCompactList()
182    
183     self.assertTrue(jsonString == pairString)
184     self.assertTrue(jsonList == pairList)
185    
186    
187     def testRuns(self):
188     """
189     Test constucting from run and list of lumis
190     """
191     runsAndLumis = {
192     1: range(1, 34) + [35] + range(37, 48),
193     2: range(49, 76) + range(77, 131) + range(133, 137)
194     }
195     runsAndLumis2 = {
196     '1': range(1, 34) + [35] + range(37, 48),
197     '2': range(49, 76) + range(77, 131) + range(133, 137)
198     }
199    
200     jsonLister = LumiList(filename = 'lumiTest.json')
201     jsonString = jsonLister.getCMSSWString()
202     jsonList = jsonLister.getCompactList()
203    
204     runLister = LumiList(runsAndLumis = runsAndLumis)
205     runString = runLister.getCMSSWString()
206     runList = runLister.getCompactList()
207    
208     runLister2 = LumiList(runsAndLumis = runsAndLumis2)
209     runList2 = runLister2.getCompactList()
210    
211     self.assertTrue(jsonString == runString)
212     self.assertTrue(jsonList == runList)
213     self.assertTrue(runList2 == runList)
214    
215    
216     def testFilter(self):
217     """
218     Test filtering of a list of lumis
219     """
220     runsAndLumis = {
221     1: range(1, 34) + [35] + range(37, 48),
222     2: range(49, 76) + range(77, 131) + range(133, 137)
223     }
224    
225     completeList = zip([1]*150, range(1, 150)) + \
226     zip([2]*150, range(1, 150)) + \
227     zip([3]*150, range(1, 150))
228    
229     smallList = zip([1]*50, range(1, 10)) + zip([2]*50, range(50, 70))
230     overlapList = zip([1]*150, range(30, 40)) + \
231     zip([2]*150, range(60, 80))
232     overlapRes = zip([1]*9, range(30, 34)) + [(1, 35)] + \
233     zip([1]*9, range(37, 40)) + \
234     zip([2]*30, range(60, 76)) + \
235     zip([2]*9, range(77, 80))
236    
237     runLister = LumiList(runsAndLumis = runsAndLumis)
238    
239     # Test a list to be filtered which is a superset of constructed list
240     filterComplete = runLister.filterLumis(completeList)
241     # Test a list to be filtered which is a subset of constructed list
242     filterSmall = runLister.filterLumis(smallList)
243     # Test a list to be filtered which is neither
244     filterOverlap = runLister.filterLumis(overlapList)
245    
246     self.assertTrue(filterComplete == runLister.getLumis())
247     self.assertTrue(filterSmall == smallList)
248     self.assertTrue(filterOverlap == overlapRes)
249    
250     def testDuplicates(self):
251     """
252     Test a list with lots of duplicates
253     """
254     result = zip([1]*100, range(1, 34) + range(37, 48))
255     lumis = zip([1]*100, range(1, 34) + range(37, 48) + range(5, 25))
256    
257     lister = LumiList(lumis = lumis)
258     self.assertTrue(lister.getLumis() == result)
259    
260     def testNull(self):
261     """
262     Test a null list
263     """
264    
265     runLister = LumiList(lumis = None)
266    
267     self.assertTrue(runLister.getCMSSWString() == '')
268     self.assertTrue(runLister.getLumis() == [])
269     self.assertTrue(runLister.getCompactList() == {})
270    
271    
272    
273     if __name__ == '__main__':
274     unittest.main()
275     '''
276    
277     # Test JSON file
278    
279     #{"1": [[1, 33], [35, 35], [37, 47]], "2": [[49, 75], [77, 130], [133, 136]]}