1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
|
#! /usr/bin/env python
#Script to parse the output of ManualO2O.py for various debugging tasks
#First use case is to debug issue with HV1/HV2 channels handling
import os,datetime, pickle
def GetLogTimestamps(ManualO2Ologfilename):
"""
This function opens the ManualO2O log chosen, and it prints out the Tmin/Tmax intervals
for the individual O2O jobs that were run.
This information can in turn be used with the function GetLogInfoByTimeStamp,
to extract from the log the (DEBUG) information only from the wanted time interval.
"""
ManualO2Olog=open(ManualO2Ologfilename,'r')
LinesCounter=0
IOVCounter=1
TmaxDict={}#This dictionary will have Tmax as keys and the lines corresponding to that Tmax as value
for line in ManualO2Olog:
LinesCounter+=1
if 'Tmin:' in line:
Tmin=line.split(':')[1].strip()
if 'Tmax:' in line:
Tmax=line.split(':')[1].strip()
#Assume that when Tmax is read Tmin was read too since we are parsing lines like this:
# Tmin: 2010 8 27 10 0 0 0
# Tmax: 2010 8 29 9 0 0 0
print("%s- Tmin: %s and Tmax: %s (number log lines %s)"%(IOVCounter,Tmin,Tmax,LinesCounter))
#Actually Tmin is not necessary... since they all will be set to the first one in the dcs_o2O_template.py used by the ManualO2O.py that created the log we're parsing.
if Tmax not in ListOfTmax.keys():
TmaxDict.update({Tmax:LinesCounter})
else:
print("This Tmax (%s) seems to be duplicated!!!"%Tmax)
LinesCounter=0
IOVCounter+=1
ManualO2Olog.close()
return TmaxDict
def GetLogInfoByTimeStamp(ManualO2Ologfilename,StartTime,StopTime):
"""
This function takes a ManualO2Ologfilename, a start and a stop timestamps (that should be
in the "YYYY M D H M S" format, e.g. Tmin: "2010 8 27 10 0 0 0",Tmax: "2010 8 27 11 0 0 0",
and it parses the given logfile to just print out the lines relevant to the given timestamp.
"""
#Open the log:
ManualO2Olog=open(ManualO2Ologfilename,'r')
#Loop to extract only the wanted lines
PrintLines=False
WantedLines=[]
for line in ManualO2Olog:
if 'Tmax:' in line and StopTime in line:
PrintLines=True
if PrintLines:
if 'Tmin:' in line:
break
else:
print(line.strip())
WantedLines.append(line)
ManualO2Olog.close()
return WantedLines
#TO BE DONE!
#implement tzinfo subclasses to get GMT1 behaviour to translate always the timestamp right...
#from datetime import timedelta, datetime, tzinfo
# import datetime
# class GMT1(datetime.tzinfo):
# def __init__(self,dt): # DST starts last Sunday in March
# d = datetime.datetime(dt.year, 4, 1) # ends last Sunday in October
# self.dston = d - datetime.timedelta(days=d.weekday() + 1)
# d = datetime.datetime(dt.year, 11, 1)
# self.dstoff = d - datetime.timedelta(days=d.weekday() + 1)
# def utcoffset(self, dt):
# return datetime.timedelta(hours=1) + self.dst(dt)
# def dst(self, dt):
# if self.dston <= dt.replace(tzinfo=None) < self.dstoff:
# return datetime.timedelta(hours=1)
# else:
# return datetime.timedelta(0)
# def tzname(self,dt):
# return "GMT +1"
#
# import time as _time
#
# STDOFFSET = datetime.timedelta(seconds = -_time.timezone)
# if _time.daylight:
# DSTOFFSET = datetime.timedelta(seconds = -_time.altzone)
# else:
# DSTOFFSET = STDOFFSET
#
# DSTDIFF = DSTOFFSET - STDOFFSET
#
# class LocalTimezone(datetime.tzinfo):
#
# def utcoffset(self, dt):
# if self._isdst(dt):
# return DSTOFFSET
# else:
# return STDOFFSET
#
# def dst(self, dt):
# if self._isdst(dt):
# return DSTDIFF
# else:
# return ZERO
#
# def tzname(self, dt):
# return _time.tzname[self._isdst(dt)]
#
# def _isdst(self, dt):
# tt = (dt.year, dt.month, dt.day,
# dt.hour, dt.minute, dt.second,
# dt.weekday(), 0, -1)
# stamp = _time.mktime(tt)
# tt = _time.localtime(stamp)
# return tt.tm_isdst > 0
#
# Local = LocalTimezone()
#
def GetQueryResults(ManualO2Ologfilename):
"""
This function takes a ManualO2Ologfilename,
and if it was run with the debug option True,
it extracts all the query results.
It uses StartTime/StopTime to identify the interval of the query (i.e. the ManualO2O.py running)
and uses the tuple (StartTime,StopTime) as a key, as stores the results rows as a list.
It returns the QueryResults dictionary that has for keys the (Tmin,Tmax) tuple, and as values lists of rows,
where the rows are dictionaries with 3 keys:
{
'change_date':datetime.datetime,
'actual_status':int,
'dpname':str
}
The idea is that any massaging of this information is done later, while this function returns the query results in bulk.
"""
print("Parsing file %s to extract query results"%ManualO2Ologfilename)
#Open the log:
ManualO2Olog=open(ManualO2Ologfilename,'r')
#Loop to extract the start and stop times
Tmin=""
Tmax=""
ReadRows=False
QueryResultsDict={}
for line in ManualO2Olog:
if 'Tmin:' in line:
if Tmin=="":#This is valid only for the first time... after the first query use the previous Tmax as Tmin.
Tmin=datetime.datetime(*[int(x) for x in (line.split(':')[1].strip()).split()])
else:
Tmin=Tmax
if 'Tmax:' in line:
Tmax=datetime.datetime(*[int(x) for x in (line.split(':')[1].strip()).split()])
#Assume that when Tmax is read Tmin was read too since we are parsing lines like this:
# Tmin: 2010 8 27 10 0 0 0
# Tmax: 2010 8 29 9 0 0 0
#print "%s- Tmin: %s and Tmax: %s (number log lines %s)"%(IOVCounter,Tmin,Tmax,LinesCounter)
if (Tmin,Tmax) not in QueryResultsDict.keys():
QueryResultsDict.update({(Tmin,Tmax):[]})
else:
print("This Tmax (%s) seems to be duplicated!!!"%Tmax)
if "Dumping all query results" in line:
ReadRows=True
if "Finished dumping query results" in line:
NumOfRows=int(line.split(",")[1].split()[0])
ReadRows=False
#Debug output:
#print "Log reports %s rows, we counted %s rows"%(NumOfRows,len(QueryResultsDict[(Tmin,Tmax)]))
if ReadRows:
Row={}
RowTokens=line.split(",")
for token in RowTokens:
if 'CHANGE_DATE' in token:
try:
#Approximate time to the second, millisecond seems just to be too much information anyway
#(one can uncomment following line to do detailed tests if needed for a short time interval)
#Row.update({'change_date':datetime.datetime.strptime(token[token.index(":")+2:-5],"%Y/%m/%d %H:%M:%S")})
#Complete timestamp including millisecond is parsed with the following commented for now line:
changeDate=datetime.datetime.strptime(token[token.index(":")+2:-1],"%Y/%m/%d %H:%M:%S.%f")
#Now introduce the check on the timezone:
#Based on the fact that we have (in Tmin/Tmax) the 1 hr interval of the query time, we can univocally determine the timezone!
#FIXME:
#Should not recalculate this at every query result... just store it!
#deltaTimezone=datetime.timedelta(seconds=((changeDate-Tmin).seconds/3600)*3600) #Using int / as modulo...
#The above is wrong! I did not realize that Tmin is also in UTC!
#Need to implement a subclass of tzinfo to handle it properly all the time... to be done later!
#For now:
deltaTimezone=datetime.timedelta(seconds=7200) #DST+GMT+1 (not valid in non DST times but ok for Run144086...
Row.update({'change_date':changeDate+deltaTimezone})
except:
print("WEIRD!\n Timestamp had a format YYYY/MM/DD HH:MM:0SS.millisecond (extra 0 tabbing for seconds!)")
print(line)
#Approximate time to the second, millisecond seems just to be too much information anyway
#(one can uncomment following line to do detailed tests if needed for a short time interval)
#Row.update({'change_date':datetime.datetime.strptime(token[token.index(":")+2:-5],"%Y/%m/%d %H:%M:0%S")})
#Complete timestamp including millisecond is parsed with the following commented for now line:
changeDate=datetime.datetime.strptime(token[token.index(":")+2:-1],"%Y/%m/%d %H:%M:0%S.%f")
#Now introduce the check on the timezone:
#Based on the fact that we have (in Tmin/Tmax) the 1 hr interval of the query time, we can univocally determine the timezone!
#FIXME:
#Should not recalculate this at every query result... just store it!
#deltaTimezone=datetime.timedelta(seconds=((changeDate-Tmin).seconds/3600)*3600) #Using int / as modulo...
#The above is wrong! I did not realize that Tmin is also in UTC!
#Need to implement a subclass of tzinfo to handle it properly all the time... to be done later!
#For now:
deltaTimezone=datetime.timedelta(seconds=7200) #DST+GMT+1 (not valid in non DST times but ok for Run144086...
Row.update({'change_date':changeDate+deltaTimezone})
if 'ACTUAL_STATUS' in token:
Row.update({'actual_status':int(token[token.index(":")+2:-1])})
if 'DPNAME' in token:
Row.update({'dpname':token[token.index(":")+2:-2]})
if len(Row)>0: #To avoid the case of an empty Row
QueryResultsDict[(Tmin,Tmax)].append(Row)
ManualO2Olog.close()
return QueryResultsDict
class TrkVoltageStatus:
"""
#How about we make a class and instantiate an object TrackerVoltageStatus that we update at each row:
#1-initialize it with a list of detID (from the most complete maps) OFF and ON (the masked ones):
#2-Has a member history, a dictionary, with keeps, by timestamp (key) a list of detIDs with their channel 0,1,2,[3] status (to decide later if we need to already handle here the checks that
# a-channel 0==1, for example by having a list of detIDs that do not have matching LV channels statuses (easy to check later, for sure it will be not empty during little transition IOVs due to different sub-second timing... we could introduce deadbands later)
# b-a LV ON/OFF bit
# c-a HV ON/OFF bit
# d-add extra (VMON, V0_SETTINGS) info in the query?
# e-add the power group turning off info in the query to check the effect
# f-add a RAMPING UP/DOWN flag on top of the conventional O2O ON/OFF?
#3-define an update(row) method that for each row takes the timestamp:
# a-if timestamp already exist, updates the channel status of the relevant detIDs contained
# b-if timestamp does not exist, creates an entry for it carrying over the information for the relevant detIDs from previous timestamp and update it with the information in the row
#4-define a getVoltageHistory(start,end) method to dump the list of IOVs, and for each IOV dump a list with the detIDs and their LV/HV status, the number of LV OFF modules and HV OFF modules, (check that there is no module with LV OFF and HV ON... basic check can be done at the update level)
"""
import datetime,sys,copy
def __init__(self,detIDPSUmapfilename="map.txt",mask_mapfilename="mask_map.txt",DetIDAliasFile="StripDetIDAlias.pkl",startTime=datetime.datetime.now(),debug=False):
"""Initialize the object with a timestamp for the start time of the query (defaults to datetime.datetime.now()) and a list of modules OFF and ON depending on masking map (for now all OFF)"""
self.debug=debug
try:
mapfile=open(detIDPSUmapfilename,'r')
maplines=mapfile.readlines()
mapfile.close()
#Extract the detIDs from the map:
self.detIDs=[int(line.split()[0]) for line in maplines]
#Check number of detIDs
#FIXME PIXEL:
#Add a flag for pixels (name of the map?) to implement the check for either detector
if len(list(set(self.detIDs)))!=15148:
print("There is an issue with the map provided: not reporting 15148 unique detIDs!")
#Parse the PSU channel part of the map
#This one does not list all channels, but follows this convention:
#-detids that are HV mapped list channel002 or channel003
#-detids that are NOT HV mapped list channel000
#-detids that are connected to HV1/HV2 crosstalking PSUs list channel999
self.PSUChannelListed=[line.split()[1] for line in maplines]
#In any case all PSU are listed so we can extract them this way:
self.PSUs=list(set([PSUChannel[:-10] for PSUChannel in self.PSUChannelListed]))
#Check number of PSUs:
if len(self.PSUs)!=1944:
print("There is an issue with the map provided: not reporting 1944 unique Power Supplies!")
#Building now a list of all PSUChannels
#(since queries to the DB will report results in DPNAMEs, i.e. PSU channels
self.PSUChannels=[]
for PSU in self.PSUs:
self.PSUChannels.append(PSU+"channel000")
self.PSUChannels.append(PSU+"channel001")
self.PSUChannels.append(PSU+"channel002")
self.PSUChannels.append(PSU+"channel003")
#This part should be unnecessary, since we do not mask any detid anymore...
#But we leave it since the possibility is in the O2O code itself still.
try:
maskfile=open(mask_mapfilename,'r')
self.masked_detIDs=[int(detID.rstrip()) for detID in maskfile]
maskfile.close()
except:
self.masked_detIDs=[] #empty list of detIDs to be "masked"
print("No mask map was provided, assuming to start from a complete Tracker OFF state")
try:
DetIDAlias=open(DetIDAliasFile,"rb")
DetIDAliasDict=pickle.load(DetIDAlias)
DetIDAlias.close()
self.DetIDAliasDict=DetIDAliasDict
except:
self.DetIDAliasDict={}
print("No valid detID-Alias map pickle file was provided!")
print("The TkrVoltageStatus object could not be initialized properly!")
print("Please use an existing detIDPSUChannel mapfilename as argument!")
sys.exit()
except:
print("Could not find detID-PSUchannel map to initialize the detIDs")
print("The TkrVoltageStatus object could not be initialized properly! Please use an existing detIDPSUChannel mapfilename as argument!")
sys.exit()
#With the information from the map build the 2 map dictionaries of interest:
#DetID->PSUChannelListed (same convention as the map)
self.DetIDPSUmap={}
for detID in self.detIDs:
self.DetIDPSUmap.update({detID:self.PSUChannelListed[self.detIDs.index(detID)]})
#PSUChannel->DetID map:
self.PSUDetIDmap={}
#This map is a bit more complicated than the DetIDPSUmap (that was just a dictionary form of the given detIDPSUChannel map passed as argument):
#Here we make a 1 to 1 map for all the PSUChannels to all detIDs connected, so for a given PSU:
#1-all detIDs listed as channel000 and as channel999 will be listed for all PSUchannels (000/001/002/003)
#2-all detIDs listed as channel002 will be listed for channel002 and for channel000/001
#3-all detIDs listed as channel003 will be listed for channel003 and for channel000/001
#NOTE:
#For Unmapped and Crosstalking channel even though we list all the detids as above (for all channels of the given PSU), we will handle them separately
#when determining whether the detids are going ON or OFF... see below.
for PSUChannel in self.PSUChannels:
if PSUChannel.endswith("0") or PSUChannel.endswith("1"): #Report all channels that match at the PSU level!
self.PSUDetIDmap.update({PSUChannel:[detid for detid in self.DetIDPSUmap.keys() if PSUChannel[:-3] in self.DetIDPSUmap[detid]]}) #PSU matching (picks all detids by PSU)
else: #For channel002 and channel003 list in this map ONLY the actual mapped ones, the unmapped or crosstalking are listed in the corresponding PSUDetIDUnmappedMap and PSUDetIDCrosstalkingMap (see below).
self.PSUDetIDmap.update({PSUChannel:[detid for detid in self.DetIDPSUmap.keys() if (PSUChannel in self.DetIDPSUmap[detid])]})
#Separate PSU-based maps for unmapped and crosstalking detids:
self.PSUDetIDUnmappedMap={}
UnmappedPSUs=list(set([psuchannel[:-10] for psuchannel in self.DetIDPSUmap.values() if psuchannel.endswith("000")]))
self.PSUDetIDCrosstalkingMap={}
CrosstalkingPSUs=list(set([psuchannel[:-10] for psuchannel in self.DetIDPSUmap.values() if psuchannel.endswith("999")]))
for PSU in self.PSUs:
if PSU in UnmappedPSUs:
self.PSUDetIDUnmappedMap.update({PSU:[detid for detid in self.DetIDPSUmap.keys() if (self.DetIDPSUmap[detid].endswith("000") and PSU in self.DetIDPSUmap[detid])]})
if PSU in CrosstalkingPSUs:
self.PSUDetIDCrosstalkingMap.update({PSU:[detid for detid in self.DetIDPSUmap.keys() if (self.DetIDPSUmap[detid].endswith("999") and PSU in self.DetIDPSUmap[detid])]})
#Need also the list of PSU channels that are unmapped and crosstalking with their status!
#Since the state for those detIDs is determined by the knowledge of the other PSU channel, we need a dictionary for both that keeps their "last value" at all times.
self.UnmappedPSUChannelStatus={}
#Initialize the dictionary with all the unmapped (only HV is relevant, channel002/003) PSU channels set to 0 (off).
for PSU in self.PSUDetIDUnmappedMap.keys():
self.UnmappedPSUChannelStatus.update({PSU+"channel002":0})
self.UnmappedPSUChannelStatus.update({PSU+"channel003":0})
self.CrosstalkingPSUChannelStatus={}
#Initialize the dictionary with all the crosstalking (only HV is relevant, channel002/003) PSU channels set to 0 (off).
for PSU in self.PSUDetIDCrosstalkingMap.keys():
self.CrosstalkingPSUChannelStatus.update({PSU+"channel002":0})
self.CrosstalkingPSUChannelStatus.update({PSU+"channel003":0})
#Now let's initialize the object (data member) we will use to keep track of the tracker status:
#Make the startTime of the initialization an attribute of the object:
self.startTime=startTime
#Basic structure of the internal history dictionary, based on query results
self.PSUChannelHistory={startTime:range(len(self.PSUChannels))}
#NOTE:
#Using the indeces to the self.PSUChannels list of PSUChannels to spare memory...
#Strategy:
#keep a timestamped list of indeces to PSUChannels
#Dynamically fetch the PSUChannels (or corresponding detIDs via PSUDetIDmap dict) on the fly whey querying the status.
#For Masked DetIDs set them always ON (since they would be detIDs that we don't know to with PSU to associate them to
#This should NOT BE THE CASE any longer, since all detIDs are now mapped at least to a PSU
#TOBEIMPLEMENTED:
#(some missing HV channel, but we treat those differently: turn them off in case either HV1/HV2 is OFF)
#(some having cross-talking PSUs, we treat those differently: turn them OFF only if both HV1/HV2 are OFF)
for detID in self.masked_detIDs:
#For each detID get the PSUChannelListed, then remove last digit (the channel number that can be 0,2 or 3)
#and then make sure to remove all channels 000,001,002,003
self.PSUChannelHistory[startTime].remove(index(detIDPSUmap[detid][-1]+'0')) #Channel000
self.PSUChannelHistory[startTime].remove(index(detIDPSUmap[detid][-1]+'1')) #Channel001
self.PSUChannelHistory[startTime].remove(index(detIDPSUmap[detid][-1]+'2')) #Channel002
self.PSUChannelHistory[startTime].remove(index(detIDPSUmap[detid][-1]+'3')) #Channel003
#Let's try to keep the one following dict that reports the number of detIDs with HV OFF and LV OFF at a given timestamp...
#Not sure even just this dict makes sense... but it is the most used information, quite minimal compare to the status of each detID
#and it provides a global IOV for the whole tracker
#NOTE:
#it won't track the case of a channel going down at the exact time another goes up!
#self.TkNumberOfDetIDsOff={startTime:(len([PSUChannel[i] for i in self.PSUChannelHistory]),len(self.detIDs))}
def updateO2OQuery(self,row):
"""Function to automatically handle the updating the of history dictionary
with the results rows from the O2O query (PSUchannel name based).
Note that row can be an actual row from SQLAlchemy from direct online DB querying
but also a dictionary extracted parsing ManualO2O.log files.
"""
#NOTE:May need to introduce IOV reduction at this level,
#but I'd prefer to handle it separately so to conserve the original data for validation purposes.
#For new IOV create a new entry in the dict and initialize it to the last IOV status
#since only change is reported with STATUS_CHANGE queries.
#First check if we care about this channel (could be a Pixel channel while we want only Strip channels or viceversa):
if row['dpname'] not in self.PSUChannels:
if self.debug:
print("Discarding results row since it is not in the currently considered map:\n%s"%row['dpname'])
return
#NOTE:
#Actually use the getIOV to allow for "asynchronous" updating:
lastTimeStamp,nextTimeStamp=self.getIOV(row['change_date'],self.PSUChannelHistory)
#Print a warning when the timeStamp is not the last one in the history!
if self.debug:
if row['change_date'] not in self.PSUChannelHistory.keys():
if nextTimeStamp!="Infinity":
print("WARNING! Asynchronous updating of the Tracker Voltage Status")
print("WARNING! Inserting an IOV between %s, and %s existing timestamps!"%(lastTimeStamp,nextTimeStamp))
print("The state will be correctly updated (if necessary) starting from the state at %s"%lastTimeStamp)
else:
print("Appending one more IOV to the PSUChannelHistory dictionary")
else:
print("Updating already present IOV with timestamp %s"%row['change_date'])
#The fact that we edit the lasttimestamp takes care of updating existing IOVs the same way as for new ones...
#Update the internal dictionary modifying the last time stamp state...
#Case of channel being ON (it's only ON if CAEN reports 1)
PSUChannelOFFList=self.PSUChannelHistory[lastTimeStamp][:]
if row['actual_status']==1: #Switching from string to int here to make sure it will be compatible with SQLAlchemy query for testing with direct DB access.
try:
PSUChannelOFFList.remove(self.PSUChannels.index(row['dpname']))
self.PSUChannelHistory.update({row['change_date']:PSUChannelOFFList})
except:
if self.debug:
print("Found a channel that turned ON but as already ON apparently!")
print(row)
else: #Case of channel being OFF (it's considered OFF in any non 1 state, ramping, error, off)
PSUChannelOFFList.append(self.PSUChannels.index(row['dpname']))
self.PSUChannelHistory.update({row['change_date']:list(set(PSUChannelOFFList))})
#First handle the detID based dict:
#Use the map to translate the DPNAME (PSUChannel) into a detid via internal map:
#CAREFUL... need to protect against pixel PSU channels being reported by the query!
#try:
# detIDList=self.PSUDetIDmap[row['dpname']]
#except:
# #FIXME: develop the pixel testing part here later...
# print "PSU channel (DPNAME) reported in not part of the wanted subdetector (only Pixel or Strips at one time)"
# print "DPNAME=%s"%row['dpname']
# detIDList=[] #Set it to empty list...
##print detID, type(detID)
#for detID in detIDList:
# #Get the previous list of channel statuses for the relevant detID:
# ModuleStatus=self.history[row['change_date']][detID]
# #Update it with the current query result row:
# #DISTINGUISH LV and HV case:
# if row['dpname'].endswith('channel000') or row['dpname'].endswith('channel001'):
# ModuleStatus[0]=row['actual_status'] #{detid:[LV,HV]} convention is ModuleStatus[0]=0 is LV OFF
# else:
# ModuleStatus[1]=row['actual_status']
# #Update the history dictionary:
# self.history[row['change_date']].update({detID:ModuleStatus})
##Add a check for the possibility of having a second IOV when only channel000/channel001 changed,
##i.e. the status did not change as a consequence for the detID based history dictionary
##(this does not affect the historyPSUChannel dictionary by definition)
#if self.history[row['change_date']]==self.history[TimeStamps['detID'][0]] and row['change_date']!=TimeStamps['detID'][0]: #This last condition is just in case something funky happens, to avoid removing good IOVs
# if self.debug:
# print "Found that the update for timestamp %s, does not change the detid status w.r.t timestamp %s"%(row['change_date'],TimeStamps['detID'][0])
# print "Eliminating the temporarily created entry in the history dictionary (it will still be logged in the historyPSUChannel dictionary"
# self.history.pop(row['change_date'])
##Then handle the PSUChannel based one:
#self.historyPSUChannel[row['change_date']].update({row['dpname']:row['actual_status']})
def updateDetIDQuery(self,row):
"""Function to automatically handle the updating of the history dictionary
with the result rows from detID based query
"""
#FIXME:
#this will have to be developed once the detID query is ready and being used in the Tracker DCS O2O
if row['change_date'] not in self.history.keys():#New timestamp (i.e. new IOV)
#For new IOV create a new entry in the dict and initialize it to the last IOV status
#since only change is reported with STATUS_CHANGE queries.
lastTimeStamp=sorted(self.history.keys()).pop(0)
self.history.update({row['change_date']:self.history[lastTimeStamp]})
#Get the previous list of channel statuses for the relevant detID:
channelStatus=self.history[row['change_date']][row['detid']]
#Update it with the current query result row:
channelStatus[row['channel']]=row['voltage_status']
#Update the history dictionary:
self.history[row['change_date']].update({row['detid']:channelStatus})
#Define the getters:
#First the TIMESTAMP based getters:
def getPSUChannelsOff(self,timestamp):
"""
Function that given a timestamp, returns the list of PSUChannels OFF, the list of PSUChannels ON and the IOV (start/stop timestamps) of the reported status.
NOTE: No distinction between HV and LV is made since all PSUChannels (000/001 and 002/003) are reported.
"""
StartTime,StopTime=self.getIOV(timestamp,self.PSUChannelHistory)
PSUChannelsOFF=map(lambda x: self.PSUChannels[x],self.PSUChannelHistory[StartTime])
PSUChannelsON=list(set(self.PSUChannels).difference(set(PSUChannelsOFF)))
return PSUChannelsOFF,PSUChannelsON,StartTime,StopTime
def getDetIDsHVOff(self,timestamp):
"""
Function that given a timestamp, returns the list of detIDs with HV OFF, the list of detIDs with HV ON and the IOV (start/stop times) of the reported status.
"""
StartTime,StopTime=self.getIOV(timestamp,self.PSUChannelHistory)
DetIDsHVOFF=[]
#A little too nasty python oneliner:
#[DetIDsHVOFF.extend(i) for i in map(lambda x: self.PSUDetIDmap[self.PSUChannels[x]],[index for index in self.PSUChannelHistory[StartTime] if (self.PSUChannels[index].endswith("2") or self.PSUChannels[index].endswith("3"))])]
#It actually does not work, since we need to consider unmapped and crosstalking channels and handle them differently, let's see:
for index in self.PSUChannelHistory[StartTime]:
#First check only for HV channels!
if self.PSUChannels[index].endswith("2") or self.PSUChannels[index].endswith("3") :
#Then check HV MAPPED channels:
if self.PSUChannels[index] in self.PSUDetIDmap.keys():
#print "Extending the list of DetIdsHVOff with the positively matched detids:",self.PSUDetIDmap[self.PSUChannels[index]]
DetIDsHVOFF.extend(self.PSUDetIDmap[self.PSUChannels[index]])
#Furthermore check the unmapped channels:
if self.PSUChannels[index][:-10] in self.PSUDetIDUnmappedMap.keys():
#To turn OFF unmapped channels there is no need to check the "other" channel:
#print "Extending the list of DetIdsHVOff with the HV unmapped (PSU-)matched detids:",self.PSUDetIDUnmappedMap[self.PSUChannels[index][:-10]]
DetIDsHVOFF.extend(self.PSUDetIDUnmappedMap[self.PSUChannels[index][:-10]])
#Further check the crosstalking channels:
if self.PSUChannels[index][:-10] in self.PSUDetIDCrosstalkingMap.keys():
#To turn OFF crosstalking channels we need to check that the other channel is OFF too!
if (self.PSUChannels.index(self.PSUChannels[index][:-1]+"2") in self.PSUChannelHistory[StartTime]) and (self.PSUChannels.index(self.PSUChannels[index][:-1]+"3") in self.PSUChannelHistory[StartTime]):
#print "Extending the list of DetIdsHVOff with the HV-CROSSTALKING (PSU-)matched detids:",self.PSUDetIDCrosstalkingMap[self.PSUChannels[index][:-10]]
DetIDsHVOFF.extend(self.PSUDetIDCrosstalkingMap[self.PSUChannels[index][:-10]])
DetIDsHVON=list(set(self.detIDs).difference(set(DetIDsHVOFF)))
return list(set(DetIDsHVOFF)),DetIDsHVON,StartTime,StopTime
def getDetIDsLVOff(self,timestamp):
"""
Function that given a timestamp, returns the list of detIDs with LV OFF, the list of detIDs with LV ON and the IOV (start/stop times) of the reported status.
"""
#Note that channels with LV OFF naturally should have HV OFF too!
StartTime,StopTime=self.getIOV(timestamp,self.PSUChannelHistory)
DetIDsLVOFF=[]
for detids in map(lambda x: self.PSUDetIDmap[self.PSUChannels[x]],[index for index in self.PSUChannelHistory[StartTime] if (self.PSUChannels[index].endswith("0") or self.PSUChannels[index].endswith("1"))]):
DetIDsLVOFF.extend(detids)
DetIDsLVON=list(set(self.detIDs).difference(set(DetIDsLVOFF)))
return list(set(DetIDsLVOFF)),DetIDsLVON,StartTime,StopTime
def getAliasesHVOff(self,timestamp):
"""
Function that given a timestamp, returns the list of (PSU) Aliases with HV OFF, the list of (PSU) Aliases with HV ON and the IOV (start/stop times) of the reported status.
"""
DetIDsHVOFF,DetIDsHVON,StartTime,StopTime=self.getDetIDsHVOff(timestamp)
AliasesHVOFF=list(set([list(self.DetIDAliasDict[detid])[0] for detid in DetIDsHVOFF])) #FIXME: check on fixing the StripDetIDAlias.pkl dictionary... no need of a set as a result! actually need to check if there is more than one element, that would be an ERROR!
AliasesHVON=list(set([list(self.DetIDAliasDict[detid])[0] for detid in DetIDsHVON]))
return AliasesHVOFF,AliasesHVON,StartTime,StopTime
def getAliasesLVOff(self,timestamp):
"""
Function that given a timestamp, returns the list of (PSU) Aliases with HV OFF, the list of (PSU) Aliases with HV ON and the IOV (start/stop times) of the reported status.
"""
DetIDsLVOFF,DetIDsLVON,StartTime,StopTime=self.getDetIDsLVOff(timestamp)
AliasesLVOFF=list(set([list(self.DetIDAliasDict[detid])[0] for detid in DetIDsLVOFF])) #FIXME: check on fixing the StripDetIDAlias.pkl dictionary... no need of a set as a result! actually need to check if there is more than one element, that would be an ERROR!
AliasesLVON=list(set([list(self.DetIDAliasDict[detid])[0] for detid in DetIDsLVON]))
return AliasesLVOFF,AliasesLVON,StartTime,StopTime
#Then the Value vs. time getters:
def getDetIDsHVOffVsTime(self):
"""
Function that returns the number of DetIDs with HV OFF vs time for all IOVs available in the PSUChannelHistory.
The results is one list of tuples [(datetime.datetime,#DetIDsHVOFF),...] and the timestamp of the last entry processed in the PSUChannelHistory.
This is important, so that the user can check until when in time the last tuple in the list is valid until (closing the last IOV).
This can be easily used to
-Do spot checks by IOV: picking a timestamp inside one of the IOVs one can use the getDetIDsHVOff function to get a list of the detIDs ON/OFF.
-Plot the graph of number of HV OFF (or ON by complementing to 15148) vs time using pyRoot
"""
#Loop over the timestamps:
DetIDsHVOffVsTime=[]
PreviousTimeStamp=None
PreviousDetIDsHVOFF=[]
for timestamp in sorted(self.PSUChannelHistory.keys()):
DetIDsHVOFF=self.getDetIDsHVOff(timestamp)[0] #Use the first returned value (DetIDsHVOFF) from getDetIDsHVOff(timestamp)!
#Check with respect to previous IOV, using set functionality, so that only relevant IOVs where there was an actual HV change are reported!
if PreviousTimeStamp:
if DetIDsHVOFF!=PreviousDetIDsHVOFF: #If there is a previous timestamp to compare to, look for differences before reporting!
DetIDsHVOffVsTime.append((timestamp,len(DetIDsHVOFF)))
else: #First IOV start... nothing to compare to:
DetIDsHVOffVsTime.append((timestamp,len(DetIDsHVOFF)))
PreviousTimeStamp=timestamp
PreviousDetIDsHVOFF=DetIDsHVOFF
LastTimeStamp=PreviousTimeStamp
return DetIDsHVOffVsTime,PreviousTimeStamp
def getDetIDsLVOffVsTime(self):
"""
Function that returns the number of DetIDs with LV OFF vs time for all IOVs available in the PSUChannelHistory.
The results is one list of tuples [(datetime.datetime,#DetIDsLVOFF),...], basically 1 entry per IOV (change in the LV channels only),
and the timestamp of the last entry processed in the PSUChannelHistory. This timestamp is important, so that the user can check until when in time the last tuple in the list is valid until (closing the last IOV).
This can be easily used to
-Do spot checks by IOV: picking a timestamp inside one of the IOVs one can use the getDetIDsHVOff function to get a list of the detIDs ON/OFF.
-Plot the graph of number of HV OFF (or ON by complementing to 15148) vs time using pyRoot
"""
#Loop over the timestamps:
DetIDsLVOffVsTime=[]
PreviousTimeStamp=None
for timestamp in sorted(self.PSUChannelHistory.keys()):
DetIDsLVOFF=set(self.getDetIDsLVOff(timestamp)[0]) #Use the first returned value (DetIDsLVOFF) from getDetIDsLVOff(timestamp)!Use set() to be able to compare the sets with != otherwise for lists, the order also makes them different!
#Check with respect to previous IOV, using set functionality, so that only relevant IOVs where there was an actual LV change are reported!
if PreviousTimeStamp:
if DetIDsLVOFF!=PreviousDetIDsLVOFF: #If there is a previous timestamp to compare to, look for differences before reporting!
DetIDsLVOffVsTime.append((timestamp,len(DetIDsLVOFF)))
else: #First IOV start... nothing to compare to:
DetIDsLVOffVsTime.append((timestamp,len(DetIDsLVOFF)))
PreviousTimeStamp=timestamp
PreviousDetIDsLVOFF=DetIDsLVOFF
LastTimeStamp=PreviousTimeStamp
return DetIDsLVOffVsTime,LastTimeStamp
#Data massagers:
def getArraysForTimePlots(self,TimeStampsValuesTuple):
"""
Function that given a tuple with (datetime.datetime,values) returns the arrays ready to the plotting vs time function (basically renders data histogram-like adding extra data points).
"""
import array, time
#Initialize the lists of timestamps (to be doubled to get the histogram/IOV look)
Timestamps=[]
Values=[]
#Loop over the list of tuples with (timestamp,numberofdetidswithLVOFF):
for item in sorted(TimeStampsValuesTuple):
#FIXME:
#NEED to check the effect/use of tzinfo to avoid issues with UTC/localtime DST etc.
#Will have to massage the datetime.datetime object in a proper way not necessary now.
#Also need to decide if we want add the milliseconds into the "timestamps for plotting in root... not straightforward so will implement only if needed. For now know that the approximation is by truncation for now!
timestamp=int(time.mktime(item[0].timetuple())) #Need to get first a time tuple, then translate it into a unix timestamp (seconds since epoc). This means no resolution under 1 second by default
if item==TimeStampsValuesTuple[0]: #First item does not need duplication
Timestamps.append(timestamp)
Value=item[1]
Values.append(Value)
else: #Add twice each timestamp except the first one (to make a histogram looking graph)
Timestamps.append(timestamp)
Values.append(Value) #Input previous value with new timestamp
Value=item[1]
Timestamps.append(timestamp)
Values.append(Value) #Input new value with new timestamp
#Need to render the two lists as arrays for pyROOT
TimestampsArray=array.array('i',Timestamps)
ValuesArray=array.array('i',Values)
return TimestampsArray,ValuesArray
def getReducedArraysForTimePlots(self,TimeStamps,Values):
"""
Implement IOV reduction based on timestamp delta, following O2O algorithm.
"""
return
#The plotters:
def plotGraphSeconds(self,TimeArray,ValuesArray,GraphTitle="Graph",YTitle="Number of channels",GraphFilename="test.gif"):
"""
Function that given an array with timestamps (massaged to introduce a second timestamp for each value to produce an histogram-looking plot) and a corresponding array with values to be plotted, a title, a Y axis title and a plot filename, produces with pyROOT a time plot and saves it locally.
The function can be used for cumulative plots (number of channels with HV/LV OFF/ON vs time) or for individual (single detID HV/LV status vs time) plots.
"""
import ROOT
canvas=ROOT.TCanvas()
graph=ROOT.TGraph(len(TimeArray),TimeArray,ValuesArray)
graph.GetXaxis().SetTimeDisplay(1)
graph.GetXaxis().SetLabelOffset(0.02)
#Set the time format for the X Axis labels depending on the total time interval of the plot!
TotalTimeIntervalSecs=TimeArray[-1]-TimeArray[0]
if TotalTimeIntervalSecs <= 120: #When zooming into less than 2 mins total interval report seconds too
graph.GetXaxis().SetTimeFormat("#splitline{ %d/%m}{%H:%M:%S}")
elif 120 < TotalTimeIntervalSecs < 6400: #When zooming into less than 2 hrs total interval report minutes too
graph.GetXaxis().SetTimeFormat("#splitline{%d/%m}{%H:%M}")
else: #When plotting more than 2 hrs only report the date and hour of day
graph.GetXaxis().SetTimeFormat("#splitline{%d/%m}{ %H}")
graph.GetYaxis().SetTitle(YTitle)
graph.GetYaxis().SetTitleOffset(1.4)
graph.SetTitle(GraphTitle)
graph.Draw("APL")
canvas.SaveAs(GraphFilename)
print("Saved graph as %s"%GraphFilename)
return
def plotPSUChannelvsTime(self,TimeArray,ValuesArray,GraphTitle="PSUChannelGraph",YTitle="Channel HV Status",GraphFilename="PSUChannel.gif"):
"""
Function that given an array with timestamps (massaged to introduce a second timestamp for each value to produce an histogram-looking plot) and a corresponding array with values to be plotted, a title, a Y axis title and a plot filename, produces with pyROOT a time plot and saves it locally.
The function can be used for cumulative plots (number of channels with HV/LV OFF/ON vs time) or for individual (single detID HV/LV status vs time) plots.
"""
import ROOT
canvas=ROOT.TCanvas()
graph=ROOT.TGraph(len(TimeArray),TimeArray,ValuesArray)
graph.GetXaxis().SetTimeDisplay(1)
graph.GetXaxis().SetLabelOffset(0.02)
#Set the time format for the X Axis labels depending on the total time interval of the plot!
TotalTimeIntervalSecs=TimeArray[-1]-TimeArray[0]
if TotalTimeIntervalSecs <= 120: #When zooming into less than 2 mins total interval report seconds too
graph.GetXaxis().SetTimeFormat("#splitline{ %d/%m}{%H:%M:%S}")
elif 120 < TotalTimeIntervalSecs < 6400: #When zooming into less than 2 hrs total interval report minutes too
graph.GetXaxis().SetTimeFormat("#splitline{%d/%m}{%H:%M}")
else: #When plotting more than 2 hrs only report the date and hour of day
graph.GetXaxis().SetTimeFormat("#splitline{%d/%m}{ %H}")
graph.GetYaxis().SetTitle(YTitle)
graph.GetYaxis().SetTitleOffset(1.4)
graph.SetTitle(GraphTitle)
graph.Draw("APL")
canvas.SaveAs(GraphFilename)
print("Saved graph as %s"%GraphFilename)
return
def plotHVOFFvsTime(self):
"""
"""
return
def plotLVOFFvsTime(self):
"""
"""
return
def plotDetIDHVOFFVsTime(self,detID):
"""
"""
return
def plotDetIDLVOFFVsTime(self,detID):
"""
"""
return
def plotDetIDHistory(self):
return
def getIOV(self,timeStamp,HistoryDict):
"""
Function that given a timeStamp return the TimeStampStart and TimeStampStop of the IOV in the wanted HistoryDict (assumed to have timestamps as keys) that contains the timestamp.
This can be used by all functions that need to access HistoryDict by timeStamp.
"""
TimeStamps=HistoryDict.keys()[:]
#Add the wanted timeStamp to the list of TimeStamps (if it is not there already!)
if timeStamp not in TimeStamps:
TimeStamps.append(timeStamp)
#Sort the list with the timestamp we added, so it will fall in between the wanted StartTime and EndTime.
TimeStamps.sort()
TimeStampStart=TimeStamps[TimeStamps.index(timeStamp)-1]
#Remember to remove it now, so that TimeStamps is still the list of available timestamps!
TimeStamps.remove(timeStamp)
else:#If the timeStamp matches one in the file, then the StartTime is that timestamp ;)
TimeStamps.sort() #this is still needed since the keys of a dictionary are not automatically sorted, but we assume TimeStamps to be sorted to spot TimeStampStop...
TimeStampStart=timeStamp
#For the TimeStampStop check the case of hitting the last IOV that is valid until infinity...
if len(TimeStamps)>TimeStamps.index(TimeStampStart)+1:
TimeStampStop=TimeStamps[TimeStamps.index(TimeStampStart)+1]
else:
TimeStampStop="Infinity"
if self.debug:
print("TimeStamp %s falls into IOV starting at %s and ending at %s"%(timeStamp,TimeStampStart,TimeStampStop))
return (TimeStampStart,TimeStampStop)
def getIOVsInTimeInterval(self,StartTime,StopTime,HistoryDict):
"""
Function that returns the IOV timestamps (ordered) contained in a given interval.
"""
#Copy and sort the timestamps in a list
TimeStamps=sorted(HistoryDict.keys()[:])
IOVsInTimeInterval=[]
#loop over them:
for timestamp in TimeStamps:
if timestamp>=StartTime and timestamp<=StopTime: #Pick only the timestamps inside the time interval specified
if self.debug:
print("Found timestamp %s in the wanted interval [%s,%s]"%(timestamp,StartTime,StopTime))
IOVsInTimeInterval.append(timestamp)
return IOVsInTimeInterval
def getReducedIOVs (self,StartTime,StopTime,HistoryDict,deltaT,maxIOVLength):
"""
Apply the reduction algorithm to the timeintervals and return them so that one can test the reduction (and do plots more easily).
"""
deltaTime=datetime.timedelta(seconds=deltaT)
maxSequenceLength=datetime.timedelta(seconds=maxIOVLength)
#Copy and sort the timestamps in a list:
TimeStamps=sorted(HistoryDict.keys()[:])
ReducedIOVs=TimeStamps[:]
PreviousTimestamp=TimeStamps[0]
SequenceStart=TimeStamps[0] #Initialization irrelevant see loop
SequenceOn=False
#Loop over timestamps:
#Note:Leave the ramp-up/down logic for later (an other function), for now we just do IOV reduction: don't care if we are ramping up or down!
for timestamp in TimeStamps[1:]: #Skip the first timestamp!(since we initialize PreviousTimeStamp to the first timestamp!)
#Check only within the interval specified:
if timestamp>=StartTime and timestamp<=StopTime:
#Check if the timestamp is within the wanted deltaT from previous timestamp
if timestamp-PreviousTimestamp<=deltaTime:
#Check if there is already an ongoing sequence of IOVs:
if SequenceOn:
#Check that this timestamp is not farther away than the maximum IOV sequence
if (timestamp-SequenceStart)<=maxSequenceLength and timestamp!=TimeStamps[-1]:#need to handle the last time stamp differently!
if self.debug:
print("Eliminating timestamp %s since it is %s (<=%s)seconds from previous timestamp %s and %s (<=%s) seconds from the IOV sequence start %s!"%(timestamp,timestamp-PreviousTimestamp,deltaTime,PreviousTimestamp,timestamp-SequenceStart,maxSequenceLength,SequenceStart))
ReducedIOVs.remove(timestamp)
elif timestamp==TimeStamps[-1]: #special case of last timestamp in the list of input timestamps!
if self.debug:
print("###Terminating the IOV sequence started with %s, since current timestamp %s is the last one in the input list of timestamps to REDUCE!"%(SequenceStart,timestamp))
else:
#Terminate the sequence (keep the timestamp):
SequenceOn=False
#Reappend the last item of the sequence (that was automatically removed not knowing it would be the last of the sequence):
ReducedIOVs.append(PreviousTimestamp)
#Re-order the list via sort():
ReducedIOVs.sort()
if self.debug:
print("###Terminating the IOV sequence started with %s, since current timestamp %s is %s seconds (>%s) away from the IOV sequence starting timestamp (%s). Re-appending the last timestamp in the sequence %s."%(SequenceStart,timestamp,timestamp-SequenceStart,maxIOVLength,PreviousTimestamp,PreviousTimestamp))
else:
#Start the sequence
SequenceOn=True
#Save the first timestamp of the sequence (it will be used to check sequence length)
if self.debug:
print("@@@Starting a new IOV sequence with previous timestamp %s (current being %s)"%(PreviousTimestamp,timestamp))
#Still get rid of the current (second in the sequence) IOV:
ReducedIOVs.remove(timestamp)
SequenceStart=PreviousTimestamp
else:
#Check if there is already an ongoing sequence of IOVs:
if SequenceOn:
#Terminate the sequence since timestamp is further than deltaT from previous timestamp:
SequenceOn=False
#Reappend the last item of the sequence (that was automatically removed not knowing it would be the last of the sequence):
ReducedIOVs.append(PreviousTimestamp)
#Re-order the list via sort():
ReducedIOVs.sort()
if self.debug:
print("$$$Terminating the IOV sequence started with %s, since current timestamp %s is %s seconds (>%s) away from the previous timestamp (%s) in the sequence. Re-appending the last timestamp in the sequence %s."%(SequenceStart,timestamp,timestamp-PreviousTimestamp,deltaT,PreviousTimestamp,PreviousTimestamp))
else:
#The following is conventional of course:
#Since we are outside the wanted time interval we should still kick out the timestamp,
#Basically we will only report a reduce sequence of timestamps within a certain interval
ReducedIOVs.remove(timestamp)
#If there is an ongoing sequence that stretches outside the StopTime:
if SequenceOn:
#Terminate sequence (should check the results if they finish with a timestamp>StopTime):
SequenceOn=False
#Reappend the last item of the sequence (that was automatically removed not knowing it would be the last of the sequence):
ReducedIOVs.append(PreviousTimestamp)
#Re-order the list via sort():
ReducedIOVs.sort()
if self.debug:
print("^^^ Terminating the IOV sequence started with %s, since current timestamp %s is no more in the wanted time interval under investigation ([%s,%s]). Sequence might have been continuing beyond the StopTime %s limit! Re-appending the last timestamp in the sequence %s."%(SequenceStart,timestamp,StartTime,StopTime,StopTime,PreviousTimestamp))
PreviousTimestamp=timestamp
return ReducedIOVs
#Messing around...
TkStatus=TrkVoltageStatus(detIDPSUmapfilename=os.path.join(os.getenv('CMSSW_BASE'),'src/CalibTracker/SiStripDCS/data/StripPSUDetIDMap_FromJan132010_Crosstalk.dat'),DetIDAliasFile=os.path.join(os.getenv('CMSSW_BASE'),'src/CalibTracker/SiStripDCS/data/StripDetIDAlias.pkl'),startTime=datetime.datetime(2010,8,27,12,00,00),debug=True)
#row1={'change_date':datetime.datetime(2010,8,27,10,37,54,732),'actual_status':1,'dpname':"cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_1/branchController04/easyCrate0/easyBoard05/channel001"}
#
#row2={'change_date':datetime.datetime(2010,8,27,11,37,54,732),'actual_status':0,'dpname':"cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_1/branchController04/easyCrate0/easyBoard05/channel001"}
#
#row3={'change_date':datetime.datetime(2010,8,27,12,37,54,732),'actual_status':1,'dpname':"cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_1/branchController04/easyCrate0/easyBoard05/channel001"}
#
#row4={'change_date':datetime.datetime(2010,8,27,10,37,54,732),'actual_status':1,'dpname':"cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_1/branchController04/easyCrate0/easyBoard05/channel002"}
#
#row5={'change_date':datetime.datetime(2010,8,27,11,37,54,732),'actual_status':0,'dpname':"cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_1/branchController04/easyCrate0/easyBoard05/channel002"}
#
#row6={'change_date':datetime.datetime(2010,8,27,12,37,54,732),'actual_status':1,'dpname':"cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_1/branchController04/easyCrate0/easyBoard05/channel002"}
#
#row7={'change_date':datetime.datetime(2010,8,27,11,37,54,732),'actual_status':0,'dpname':"cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_1/branchController04/easyCrate0/easyBoard05/channel002"}
#
#row8={'change_date':datetime.datetime(2010,8,27,10,37,54,735),'actual_status':1,'dpname':"cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_1/branchController04/easyCrate0/easyBoard05/channel002"}
#
##Initialization IOV:
#print "detID IOVs",TkStatus.history.keys()
#print "PSUChannel IOVs",TkStatus.historyPSUChannel.keys()
#
#TkStatus.updateO2OQuery(row1)
#print "detID IOVs",TkStatus.history.keys()
#print "PSUChannel IOVs",TkStatus.historyPSUChannel.keys()
#
#TkStatus.updateO2OQuery(row2)
#print "detID IOVs",TkStatus.history.keys()
#print "PSUChannel IOVs",TkStatus.historyPSUChannel.keys()
#
#TkStatus.updateO2OQuery(row3)
#print "detID IOVs",TkStatus.history.keys()
#print "PSUChannel IOVs",TkStatus.historyPSUChannel.keys()
#
#TkStatus.updateO2OQuery(row4)
#print "detID IOVs",TkStatus.history.keys()
#print "PSUChannel IOVs",TkStatus.historyPSUChannel.keys()
#
#TkStatus.updateO2OQuery(row5)
#print "detID IOVs",TkStatus.history.keys()
#print "PSUChannel IOVs",TkStatus.historyPSUChannel.keys()
#
#TkStatus.updateO2OQuery(row6)
#print "detID IOVs",TkStatus.history.keys()
#print "PSUChannel IOVs",TkStatus.historyPSUChannel.keys()
#
#TkStatus.updateO2OQuery(row7)
#print "detID IOVs",TkStatus.history.keys()
#print "PSUChannel IOVs",TkStatus.historyPSUChannel.keys()
#
#TkStatus.updateO2OQuery(row8)
#print "detID IOVs",TkStatus.history.keys()
#print "PSUChannel IOVs",TkStatus.historyPSUChannel.keys()
#
#TkStatus.getHVOnModules(datetime.datetime(2010, 8, 27, 10, 00, 54, 732))
#Test Crosstalking channels handling:
#rowCross1={'change_date':datetime.datetime(2010,8,27,10,37,54,732),'actual_status':1,'dpname':"cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_9/branchController04/easyCrate0/easyBoard09/channel002"}
#rowCross2={'change_date':datetime.datetime(2010,8,27,10,37,57,732),'actual_status':1,'dpname':"cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_9/branchController04/easyCrate0/easyBoard09/channel003"}
#rowCross3={'change_date':datetime.datetime(2010,8,27,10,38,00,732),'actual_status':0,'dpname':"cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_9/branchController04/easyCrate0/easyBoard09/channel002"}
#rowCross4={'change_date':datetime.datetime(2010,8,27,10,38,05,732),'actual_status':0,'dpname':"cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_9/branchController04/easyCrate0/easyBoard09/channel003"}
#print "Starting number of PSUChannels OFF is %s and of DetIDs ON is %s"%(len(TkStatus.PSUChannelHistory[TkStatus.getIOV(datetime.datetime(2010,8,27,10,30,00),TkStatus.PSUChannelHistory)[0]]),len(TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010,8,27,10,30,00),TkStatus.PSUChannelHistory)[0])[1]))
#TkStatus.updateO2OQuery(rowCross1)
#print "Turning ON HV crosstalking channel cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_9/branchController04/easyCrate0/easyBoard09/channel002 number of channels OFF is %s"%len(TkStatus.PSUChannelHistory[TkStatus.getIOV(datetime.datetime(2010,8,27,10,37,55),TkStatus.PSUChannelHistory)[0]])
#print "and related number of detIDs listed as ON is %s"%len(TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010,8,27,10,37,55),TkStatus.PSUChannelHistory)[0])[1])
#print TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010,8,27,10,37,55),TkStatus.PSUChannelHistory)[0])[1]
#TkStatus.updateO2OQuery(rowCross2)
#print "Turning ON HV crosstalking channel cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_9/branchController04/easyCrate0/easyBoard09/channel003 number of channels OFF is %s"%len(TkStatus.PSUChannelHistory[TkStatus.getIOV(datetime.datetime(2010,8,27,10,37,58),TkStatus.PSUChannelHistory)[0]])
#print "and related number of detIDs listed as ON is %s"%len(TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010, 8, 27, 10, 37, 58),TkStatus.PSUChannelHistory)[0])[1])
#print TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010, 8, 27, 10, 37, 58),TkStatus.PSUChannelHistory)[0])[1]
#TkStatus.updateO2OQuery(rowCross3)
#print "Turning OFF HV crosstalking channel cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_9/branchController04/easyCrate0/easyBoard09/channel002 number of channels off is %s"%len(TkStatus.PSUChannelHistory[TkStatus.getIOV(datetime.datetime(2010,8,27,10,38,02),TkStatus.PSUChannelHistory)[0]])
#print "and related number of detIDs listed as ON is %s"%len(TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010, 8, 27, 10, 38, 02),TkStatus.PSUChannelHistory)[0])[1])
#print TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010, 8, 27, 10, 38, 02),TkStatus.PSUChannelHistory)[0])[1]
#TkStatus.updateO2OQuery(rowCross4)
#print "Turning OFF HV crosstalking channel cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_9/branchController04/easyCrate0/easyBoard09/channel003 number of channels off is %s"%len(TkStatus.PSUChannelHistory[TkStatus.getIOV(datetime.datetime(2010,8,27,10,38,07),TkStatus.PSUChannelHistory)[0]])
#print "and related number of detIDs listed as ON is %s"%len(TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010, 8, 27, 10, 38, 07),TkStatus.PSUChannelHistory)[0])[1])
#print TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010, 8, 27, 10, 38, 07),TkStatus.PSUChannelHistory)[0])[1]
#
##Test Unmapped channels handling:
#rowUnmap1={'change_date':datetime.datetime(2010,8,27,11,37,54,732),'actual_status':1,'dpname':"cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_2/branchController05/easyCrate1/easyBoard07/channel002"}
#rowUnmap2={'change_date':datetime.datetime(2010,8,27,11,37,57,732),'actual_status':1,'dpname':"cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_2/branchController05/easyCrate1/easyBoard07/channel003"}
#rowUnmap3={'change_date':datetime.datetime(2010,8,27,11,38,00,732),'actual_status':0,'dpname':"cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_2/branchController05/easyCrate1/easyBoard07/channel002"}
#rowUnmap4={'change_date':datetime.datetime(2010,8,27,11,38,05,732),'actual_status':0,'dpname':"cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_2/branchController05/easyCrate1/easyBoard07/channel003"}
#print "Starting number of PSUChannels OFF is %s and of DetIDs ON is %s"%(len(TkStatus.PSUChannelHistory[TkStatus.getIOV(datetime.datetime(2010,8,27,11,30,00),TkStatus.PSUChannelHistory)[0]]),len(TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010,8,27,11,30,00),TkStatus.PSUChannelHistory)[0])[1]))
#TkStatus.updateO2OQuery(rowUnmap1)
#print "Turning ON HV crosstalking channel cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_2/branchController05/easyCrate1/easyBoard07/channel002 number of channels OFF is %s"%len(TkStatus.PSUChannelHistory[TkStatus.getIOV(datetime.datetime(2010,8,27,11,37,55),TkStatus.PSUChannelHistory)[0]])
#print "and related number of detIDs listed as ON is %s"%len(TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010,8,27,11,37,55),TkStatus.PSUChannelHistory)[0])[1])
#print TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010,8,27,11,37,55),TkStatus.PSUChannelHistory)[0])[1]
#TkStatus.updateO2OQuery(rowUnmap2)
#print "Turning ON HV crosstalking channel cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_2/branchController05/easyCrate1/easyBoard07/channel003 number of channels OFF is %s"%len(TkStatus.PSUChannelHistory[TkStatus.getIOV(datetime.datetime(2010,8,27,11,37,58),TkStatus.PSUChannelHistory)[0]])
#print "and related number of detIDs listed as ON is %s"%len(TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010, 8, 27, 11, 37, 58),TkStatus.PSUChannelHistory)[0])[1])
#print TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010, 8, 27, 11, 37, 58),TkStatus.PSUChannelHistory)[0])[1]
#TkStatus.updateO2OQuery(rowUnmap3)
#print "Turning OFF HV crosstalking channel cms_trk_dcs_02:CAEN/CMS_TRACKER_SY1527_2/branchController05/easyCrate1/easyBoard07/channel002 number of channels off is %s"%len(TkStatus.PSUChannelHistory[TkStatus.getIOV(datetime.datetime(2010,8,27,11,38,02),TkStatus.PSUChannelHistory)[0]])
#print "and related number of detIDs listed as ON is %s"%len(TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010, 8, 27, 11, 38, 02),TkStatus.PSUChannelHistory)[0])[1])
#print TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010, 8, 27, 11, 38, 02),TkStatus.PSUChannelHistory)[0])[1]
#TkStatus.updateO2OQuery(rowUnmap4)
#print "Turning OFF HV crosstalking channel cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_9/branchController04/easyCrate0/easyBoard09/channel003 number of channels off is %s"%len(TkStatus.PSUChannelHistory[TkStatus.getIOV(datetime.datetime(2010,8,27,11,38,07),TkStatus.PSUChannelHistory)[0]])
#print "and related number of detIDs listed as ON is %s"%len(TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010, 8, 27, 11, 38, 07),TkStatus.PSUChannelHistory)[0])[1])
#print TkStatus.getDetIDsHVOff(TkStatus.getIOV(datetime.datetime(2010, 8, 27, 11, 38, 07),TkStatus.PSUChannelHistory)[0])[1]
#
#Test function that parses ManualO2O.log to get by timeinterval the results of each O2O query
QueryResults=GetQueryResults("ManualO2O.log")
#QueryResultsPickle=open("QueryResultsDict.pkl","wb")
#pickle.dump(QueryResults,QueryResultsPickle)
#Now that we have this we can do:
counter=0
hours=72 #introduced to test only a few hours, setting it to 1000 to process ALL IOVS.
for interval in sorted(QueryResults.keys()):
counter+=1
if counter<hours: #Hours
print("Updating TkStatus with query results for time interval %s to %s"%interval)
for row in QueryResults[interval]:
TkStatus.updateO2OQuery(row)
print(len(TkStatus.PSUChannelHistory))
if counter-hours>0:
print("Number of intervals skipped %s"%(counter-hours))
#Dump the PSUChannelHistory dictionary!
#TkHistoryPickle=open("TkPSUChannelHistory.pkl","wb")
#pickle.dump(TkStatus.PSUChannelHistory,TkHistoryPickle)
#TkHistoryPickle.close()
#
#for timestamp in sorted(TkStatus.PSUChannelHistory.keys()):
# if len(TkStatus.PSUChannelHistory[timestamp])<4000:
# print len(TkStatus.PSUChannelHistory[timestamp]),timestamp
#Test getters as I implement them:
#ChannelsOFF,ChannelsON,Start,Stop=TkStatus.getPSUChannelsOff(datetime.datetime(2010,8,27,10,38,26,700000))
#print "IOV: %s -> %s"%(Start,Stop)
#print "Number of PSU channels reported OFF: %s"%len(ChannelsOFF)
#print "Number of PSU channels reported ON: %s"%len(ChannelsON)
#DetIDsHVOFF,DetIDsHVON,Start,Stop=TkStatus.getDetIDsHVOff(datetime.datetime(2010,8,27,10,38,26,700000))
#print "IOV: %s -> %s"%(Start,Stop)
#print "Number of detID reported with HV OFF: %s"%len(DetIDsHVOFF)
#print "Number of detID reported with HV ON: %s"%len(DetIDsHVON)
#DetIDsLVOFF,DetIDsLVON,Start,Stop=TkStatus.getDetIDsLVOff(datetime.datetime(2010,8,27,10,38,26,700000))
#print "IOV: %s -> %s"%(Start,Stop)
#print "Number of detID reported with LV OFF: %s"%len(DetIDsLVOFF)
#print "Number of detID reported LV ON: %s"%len(DetIDsLVON)
#AliasesHVOFF,AliasesHVON,Start,Stop=TkStatus.getAliasesHVOff(datetime.datetime(2010,8,27,10,38,26,700000))
#print "IOV: %s -> %s"%(Start,Stop)
#print "Number of aliases reported with HV OFF: %s"%len(AliasesHVOFF)
#print "Number of aliases reported HV ON: %s"%len(AliasesHVON)
#AliasesLVOFF,AliasesLVON,Start,Stop=TkStatus.getAliasesLVOff(datetime.datetime(2010,8,27,10,38,26,700000))
#print "IOV: %s -> %s"%(Start,Stop)
#print "Number of aliases reported with LV OFF: %s"%len(AliasesLVOFF)
#print "Number of aliases reported LV ON: %s"%len(AliasesLVON)
#Check the number of channels off in the Run144086 IOV:
#DetIDsHVOFF,DetIDsHVON,Start,Stop=TkStatus.getDetIDsHVOff(datetime.datetime(2010,8,29,8,0,0,0))
#print "IOV: %s -> %s"%(Start,Stop)
#print "Number of detID reported with HV OFF: %s"%len(DetIDsHVOFF)
#print "Number of detID reported with HV ON: %s"%len(DetIDsHVON)
#DetIDsLVOFF,DetIDsLVON,Start,Stop=TkStatus.getDetIDsLVOff(datetime.datetime(2010,8,29,8,0,0,0))
#print "IOV: %s -> %s"%(Start,Stop)
#print "Number of detID reported with LV OFF: %s"%len(DetIDsLVOFF)
#print "Number of detID reported LV ON: %s"%len(DetIDsLVON)
#Now implement the following test:
#-Read in all the logs (either the DetVOffReaderDebug or the ones produced by the MakeTkMaps
#-Extract the IOV from the filename
#-Get the corresponding IOVs list from the PSUChannelHistory
#-Print out the number of DetIDs with LV ON/OFF (and of crosstalking and unmapped detids separately)
#-DetID comparison for each IOV (picking the stable one in PSUChannelHistory)
#-Implement the reduction as a method of TrkVoltageStatus that takes as argument deltaTmin and MaxIOVlength
#and returns the lists of HV and LV channels off (IOVs are for any change of either HV or LV PSU channels)
#-Check the reduction result (number of IOVs, suppression during ramp up/down, ...)
#-DetID comparison for each IOV
#-Implement the direct query check of the query results and report anomalies (old results at the interface of the 1-hour queries:
# -Get the query dumped by Coral by turning on verbosity and off
# -Pick the query from the code too
#-Mapping part, integrate results of dictionaries from HV mapping code from Ben, dump all relevant dictionaries
#Cross-check stuff with cabling info?
#Check time changes and effect DST etc timezone issues and plotting limitations...
#Add number of ramp up/downs plots minima/maxima of HV/LV OFF/ON
#Look out for individual channels going down (trips) instead of full ramping
#Talk to Online guys about cross-talking and HV mapping
#Look into the query with the turn off commands and into giving the map for the new table to Robert
#Talk with Frank about extra info needed
#Look into Pixel integration extras
## #This next step is REALLY SLOW if there are thousands of IOVs to handle!
##
## #Turn debug off to avoid a lot of printouts from getIOV:
## TkStatus.debug=False
## DetIDsHVOffVsTime,LastHVTimeStamp=TkStatus.getDetIDsHVOffVsTime()
## TkStatus.debug=True
## print "There are %s timestamps for DetIDs HV Off. The last timestamp (end of last IOV) is %s"%(len(DetIDsHVOffVsTime),LastHVTimeStamp)
##
## #Turn debug off to avoid a lot of printouts from getIOV:
## TkStatus.debug=False
## DetIDsLVOffVsTime,LastLVTimeStamp=TkStatus.getDetIDsLVOffVsTime()
## TkStatus.debug=True
## print "There are %s timestamps for DetIDs LV Off. The last timestamp (end of last IOV) is %s"%(len(DetIDsLVOffVsTime),LastLVTimeStamp)
##
## #Prepare the data for LV/HV OFF Graph plotting with PyROOT:
## import array, time
##
## #Initialize the lists of timestamps (to be doubled to get the histogram/IOV look)
## LVOFFTimestamps=[]
## NumberOfLVOFFChannels=[]
## #Loop over the list of tuples with (timestamp,numberofdetidswithLVOFF):
## for item in sorted(DetIDsLVOffVsTime):
## #FIXME:
## #NEED to check the effect/use of tzinfo to avoid issues with UTC/localtime DST etc.
## #Will have to massage the datetime.datetime object in a proper way not necessary now.
## #Also need to decide if we want add the milliseconds into the "timestamps for plotting in root... not straightforward so will implement only if needed. For now know that the approximation is by truncation for now!
## timestamp=int(time.mktime(item[0].timetuple())) #Need to get first a time tuple, then translate it into a unix timestamp (seconds since epoc). This means no resolution under 1 second by default
## if item==DetIDsLVOffVsTime[0]: #First item does not need duplication
## LVOFFTimestamps.append(timestamp)
## LVOff=item[1]
## NumberOfLVOFFChannels.append(LVOff)
## else: #Add twice each timestamp except the first one (to make a histogram looking graph)
## LVOFFTimestamps.append(timestamp)
## NumberOfLVOFFChannels.append(LVOff) #Input previous value with new timestamp
## LVOff=item[1]
## LVOFFTimestamps.append(timestamp)
## NumberOfLVOFFChannels.append(LVOff) #Input new value with new timestamp
##
## LVOFFTimestampsArray=array.array('i',LVOFFTimestamps)
## NumberOfLVOFFChannelsArray=array.array('i',NumberOfLVOFFChannels)
##
## #Initialize the lists of timestamps (to be doubled to get the histogram/IOV look)
## HVOFFTimestamps=[]
## NumberOfHVOFFChannels=[]
## #Loop over the list of tuples with (timestamp,numberofdetidswithHVOFF):
## for item in sorted(DetIDsHVOffVsTime):
## timestamp=int(time.mktime(item[0].timetuple()))
## if item==DetIDsHVOffVsTime[0]: #First item does not need duplication
## HVOFFTimestamps.append(timestamp)
## HVOff=item[1]
## NumberOfHVOFFChannels.append(HVOff)
## else: #Add twice each timestamp except the first one (to make a histogram looking graph)
## HVOFFTimestamps.append(timestamp)
## NumberOfHVOFFChannels.append(HVOff) #Input previous value with new timestamp
## HVOff=item[1]
## HVOFFTimestamps.append(timestamp)
## NumberOfHVOFFChannels.append(HVOff) #Input new value with new timestamp
##
## HVOFFTimestampsArray=array.array('i',HVOFFTimestamps) #NEED TO USE DOUBLES if we want the microseconds!!!! or it screws up approximating the timestamp
## NumberOfHVOFFChannelsArray=array.array('i',NumberOfHVOFFChannels)
##
## #Testing the plotting function
## TkStatus.plotGraphSeconds(LVOFFTimestampsArray,NumberOfLVOFFChannelsArray,GraphTitle="Modules with LV OFF",YTitle="Number of modules with LV OFF",GraphFilename="Test2.gif")
## #TkStatus.plotGraphSeconds(LVOFFTimestampsArray,NumberOfLVOFFChannelsArray,"Modules with LV OFF","Number of modules with LV OFF","Test2.gif")
#Develop the Validation based on the TkStatus object on one side and the actual output of the O2O reader (CheckAllIOVs) in the current dir:
#FIXME:
#Issues to look into:
#1-first IOV not starting from beginning of the query: that should always be the case!
#2-Reduction seems to not be doing the right thing...
#3-timestamp timezone translation...
#Get the ReducedIOVsTimestamps (using the TkVoltage.getReducedIOVs() using the same deltaT=15s, and maxIOVSequenceLength=120s):
ReducedIOVsTimestamps=TkStatus.getReducedIOVs(datetime.datetime(2010, 8, 27, 12, 0),datetime.datetime(2010, 8, 29, 17, 45),TkStatus.PSUChannelHistory,15,120)
#Print out for debugging the reduced timestamps with their index (to see when a sequence is present) and the number of LV/HV channels OFF for the given timestamp in the TkStatus object!
print("Dumping ReducedIOVsTimestamps and the corresponding timestamp index and number of HV/LV channels off:")
for timestamp in ReducedIOVsTimestamps:
TkStatus.debug=False
print(timestamp,sorted(TkStatus.PSUChannelHistory.keys()).index(timestamp),len(TkStatus.getDetIDsHVOff(timestamp)[0]), len(TkStatus.getDetIDsLVOff(timestamp)[0]))
#Following function will be moved inside the TkVoltageStatus class once it's perfected:
def ReducedIOVsHistory(ReducedIOVsTimestamps):
"""
Function that given a list of reduced IOVs timestamps (output of getReducedIOVs()), analyses the timestamps to identify the IOV sequences and treats them differently when ramping-up or ramping-down, to return a dictionary that has timestamp as a key and the list of LV and HV channels OFF, that can be compared with the content of the CheckAllIOVs output DetVOffReaderDebug logs for validation.
"""
AllTimestamps=sorted(TkStatus.PSUChannelHistory.keys())
PreviousTimestampIndex=-1
ReducedIOVsDict={}
for timestamp in ReducedIOVsTimestamps:
if AllTimestamps.index(timestamp)!=(PreviousTimestampIndex+1): #Sequence end!
#Get the current timestamp LVOff channels:
LVOffEnd=TkStatus.getDetIDsLVOff(timestamp)[0]
#and the LV Off ones for the previous timestamp (beginning of the sequence):
LVOffStart=TkStatus.getDetIDsLVOff(AllTimestamps[PreviousTimestampIndex])[0]
#Get the current timestamp HVOff channels:
HVOffEnd=TkStatus.getDetIDsHVOff(timestamp)[0]
#and the HV Off ones for the previous timestamp (beginning of the sequence):
HVOffStart=TkStatus.getDetIDsHVOff(AllTimestamps[PreviousTimestampIndex])[0]
#This can be complicated... let's go for the same approach as the official O2O reduction
#We can just test if the other conditions not captured by the ifs ever happen!
#Turning OFF case:
if len(LVOffEnd)>len(LVOffStart) or len(HVOffEnd)>len(HVOffStart):
ReducedIOVsDict.update({AllTimestamps[PreviousTimestampIndex]:(TkStatus.getDetIDsHVOff(timestamp)[0],TkStatus.getDetIDsLVOff(timestamp)[0])}) #use the LVOff/HVOff form the last element in the sequence and set the first element of the sequence to it!
#Turning (Staying) ON case:
#Nothing special to do (same as not a sequence)! We're happy with having thrown away all the intermediate timestamps, and keep the validity of the first timestamp of the sequence throughout the sequence:
#For all timestamps reported (if they are a start of a sequence they will be "overwritten" once we process the end of the sequence timestamp) in particular also the end of a ramp-up sequence does not need no special treatement:
#Actually check if the LV Off or HVOff are the same as the previous timestamp: if they are do nothing, if they are not then add an IOV...
if set(TkStatus.getDetIDsHVOff(timestamp)[0])!=set(TkStatus.getDetIDsHVOff(AllTimestamps[PreviousTimestampIndex])[0]) or set(TkStatus.getDetIDsLVOff(timestamp)[0])!=set(TkStatus.getDetIDsLVOff(AllTimestamps[PreviousTimestampIndex])[0]):
ReducedIOVsDict.update({timestamp:(TkStatus.getDetIDsHVOff(timestamp)[0],TkStatus.getDetIDsLVOff(timestamp)[0])})
PreviousTimestampIndex=AllTimestamps.index(timestamp)
return ReducedIOVsDict
#Now using the ReducedIOVs timestamps we can get the actual ReducedIOVs using the same algorithm as the O2O (implemented in the function ReducedIOVsHistory):
ValidationReducedIOVsHistory=ReducedIOVsHistory(ReducedIOVsTimestamps)
#Print out for debugging the timestamp, the number of HV/LV channels off from the TkStatus object for each of the REDUCED timestamps (AGAIN)
#for timestamp in ReducedIOVsTimestamps:
# print timestamp,len(TkStatus.getDetIDsHVOff(timestamp)[0]),len(TkStatus.getDetIDsLVOff(timestamp)[0])
#Print out for debugging the timestamp, the number of HV/LV channels OFF from the ValidationReducedIOVsHistory object directly!
#i=0
print("Dumping ValidationReducedIOVsHistory contents:")
for timestamp in sorted(ValidationReducedIOVsHistory.keys()):
print(timestamp, len(ValidationReducedIOVsHistory[timestamp][0]),len(ValidationReducedIOVsHistory[timestamp][1]))#,sorted(O2OReducedIOVs.keys())[i],len(O2OReducedIOVs[sorted(O2OReducedIOVs.keys())[i]][0]),len(O2OReducedIOVs[sorted(O2OReducedIOVs.keys())[i]][1])
# i=i+1
#for i in range(42):
# print sorted(ValidationReducedIOVsHistory.keys())[i],sorted(O2OReducedIOVs.keys())[i]
#Now extract the DetVOffInfo from the logfiles directly and then we can compare!
#Cut&Paste of a quick and dirty script that reads the CheckAllIOVS.py output (ReaderDebug) logs and produces an O2OData dictionary
#that has timestamps (from filename) as keys and a tuple (HVOff,LVOff) as value, where HVOff and LVOff are lists of detids that have HV/LV off respectively.
#The union of the two would be the total number of detids listed as OFF (in either way, OFF-OFF or OFF-ON)
#Can implement a direct IOV comparison using the reduction above (need to be careful on the matching of IOVs)
#import datetime
def ExtractDetVOffInfo(directory=os.getcwd()):
"""
Function that given a directory (defaults to the local one in case no dir indicated), parses all local DetVOffReaderDebug*.log files and returna a dictionary with timestamps for keys and a tuple with the list of LV and HV channels OFF (LVOff,HVOff).
"""
ls=os.listdir(directory)
TimesLogs=[]
O2OData={}
for log in ls:
if "DetVOffReaderDebug__FROM" in log:
(start,end)=log[:-4].split("FROM_")[1].split("_TO_")
TimeStamp=datetime.datetime.strptime(start.replace("__","_0"),"%a_%b_%d_%H_%M_%S_%Y")
#print start,TimeStamp
file=open(log,'r')
filelines=file.readlines()
file.close()
LVOff=[]
HVOff=[]
for line in filelines:
#print line
if "OFF" in line:
detid,hv,lv=line.split()
#print line,detid,hv,lv
if hv=="OFF":
HVOff.append(int(detid))
if lv=="OFF":
LVOff.append(int(detid))
O2OData.update({TimeStamp:(HVOff,LVOff)})
return O2OData
#Extract the O2O Reduced IOVs data from the logfiles in the current directory
O2OReducedIOVs=ExtractDetVOffInfo()
#Print out for debugging the timestamp, the number of HV/LV channels OFF reported by the O2O
print("Dumping the O2OReducedIOVs contents:")
for timestamp in sorted(O2OReducedIOVs.keys()):
print(timestamp, len(O2OReducedIOVs[timestamp][0]),len(O2OReducedIOVs[timestamp][1]))#,len(TkStatus.getDetIDsHVOff(TkStatus.getIOV(timestamp,TkStatus.PSUChannelHistory)[0])[0]), len(TkStatus.getDetIDsLVOff(TkStatus.getIOV(timestamp,TkStatus.PSUChannelHistory)[0])[0])
#Compare the actual detids after doing the reduction the way we want to do it!
# len(TkStatus.getDetIDsHVOff(sorted(TkStatus.PSUChannelHistory.keys())[-1])[0])
#Now compare the reduced histories:
def CompareReducedDetIDs(FirstDict,SecondDict):
"""
Function that given 2 Dictionaries (key=timestamp, value=(LVOff,HVOff)) loops through the first one and compared the content of its IOVs with the IOV in the other dict that overlaps with it.
"""
DifferenceDict={}
for timestamp in sorted(FirstDict.keys()):
if timestamp.replace(microsecond=0) in SecondDict.keys():
secondtimestamp=timestamp.replace(microsecond=0)
print("Timestamp %s is present in both Dictionaries!"%timestamp)
else:
secondtimestamps=sorted(SecondDict.keys())
secondtimestamps.append(timestamp)
secondtimestamps.sort()
if secondtimestamps.index(timestamp)!=0:#To avoid wrapping up to the end of the list of timestamps!!!
secondtimestamp=secondtimestamps[secondtimestamps.index(timestamp)-1]
else:#Default to the earliest timestamp in the second dictionary...
secondtimestamp=secondtimestamps[secondtimestamps.index(timestamp)+1]
print("Comparing the IOV with timestamp %s (1st dict) with IOV with timestamp %s (2nd dict)"%(timestamp,secondtimestamp))
if set(map(lambda x:int(x),FirstDict[timestamp][0]))!=set(map(lambda x:int(x),SecondDict[secondtimestamp][0])) or set(map(lambda x:int(x),FirstDict[timestamp][1]))!=set(map(lambda x:int(x),SecondDict[secondtimestamp][1])): #Change!
if len(set(FirstDict[timestamp][0]))<=len(set(SecondDict[secondtimestamp][0])):
differenceHV=set(map(lambda x:int(x),SecondDict[secondtimestamp][0]))-set(map(lambda x:int(x),FirstDict[timestamp][0]))
else:
#elif len(set(SecondDict[secondtimestamp][0]))<len(set(FirstDict[timestamp][0])):
differenceHV=set(map(lambda x:int(x),FirstDict[timestamp][0]))-set(map(lambda x:int(x),SecondDict[secondtimestamp][0]))
#else:
# print "SCREAM! Something weird going on one of the two should be a subset of the other!"
# differenceLV=set([])
# differenceHV=set([])
if len(set(FirstDict[timestamp][1]))<=len(set(SecondDict[secondtimestamp][1])):
differenceLV=set(map(lambda x:int(x),SecondDict[secondtimestamp][1]))-set(map(lambda x:int(x),FirstDict[timestamp][1]))
else:
#elif set(SecondDict[secondtimestamp][1]).issubset(set(FirstDict[timestamp][1])):
differenceLV=set(map(lambda x:int(x),FirstDict[timestamp][1]))-set(map(lambda x:int(x),SecondDict[secondtimestamp][1]))
#else:
# print "SCREAM! Something weird going on one of the two should be a subset of the other!"
# differenceLV=set([])
# differenceHV=set([])
DifferenceDict.update({(timestamp,secondtimestamp):(differenceHV,differenceLV)})
print("Difference in timestamp %s (corresponding to %s):"%(timestamp,secondtimestamp))
#print "LV OFF:"
#for LVChannel in differenceLV:
# print LVChannel
#print "HV OFF:"
#for HVChannel in differenceHV:
# print HVChannel
else:
print("Timestamp %s is identical in both dictionaries"%timestamp)
return DifferenceDict
Comparison=CompareReducedDetIDs(ValidationReducedIOVsHistory,O2OReducedIOVs)
print("Dumping the results of the comparisons of the two dictionaries:")
for timestamps in sorted(Comparison.keys()):
print(timestamps, Comparison[timestamps])
if Comparison[timestamps][0]:
print("HV:")
if Comparison[timestamps][0].issubset(set(O2OReducedIOVs[timestamps[1]][0])):
print("Only in O2O Dict!")
else:
print("Only in Validation Dict!")
for detid in Comparison[timestamps][0]:
print(detid,TkStatus.DetIDAliasDict[detid])
if Comparison[timestamps][1]:
print("LV:")
if Comparison[timestamps][1].issubset(set(O2OReducedIOVs[timestamps[1]][1])):
print("Only in O2O Dict!")
else:
print("Only in Validation Dict!")
for detid in Comparison[timestamps][1]:
print(detid,TkStatus.DetIDAliasDict[detid])
#Add a check with the query using sqlalchemy
#Add a check for channels that never show updates in the queries (even when several ramp cycles happened)
#Add a check that inside the sequence change is consistently up or down
#Check of the direct DB query:
#Need to first run another python script (using the local python of cmstrko2ovm02 that has sqlalchemy, cx-oracle etc) that dumps a pkl with a list of the result rows of the O2O query....
TkStatusFromQuery=TrkVoltageStatus(detIDPSUmapfilename=os.path.join(os.getenv('CMSSW_BASE'),'src/CalibTracker/SiStripDCS/data/StripPSUDetIDMap_FromJan132010_Crosstalk.dat'),DetIDAliasFile=os.path.join(os.getenv('CMSSW_BASE'),'src/CalibTracker/SiStripDCS/data/StripDetIDAlias.pkl'),startTime=datetime.datetime(2010,8,27,10,00,00),debug=True)
DBQueryPickle=open('/afs/cern.ch/user/g/gbenelli/scratch0/O2OValidation/QueryResults.pkl','rb')
DBQueryResults=[]
DBQueryResults=pickle.load(DBQueryPickle)
DBQueryPickle.close()
for row in DBQueryResults:
TkStatusFromQuery.updateO2OQuery(row)
print(len(TkStatusFromQuery.PSUChannelHistory))
delta=datetime.timedelta(seconds=7200)
counter=0
DifferingTimestamps=[]
for timestamp in sorted(TkStatus.PSUChannelHistory.keys()):
if timestamp-delta!=sorted(TkStatusFromQuery.PSUChannelHistory.keys())[counter]:
print(timestamp, sorted(TkStatusFromQuery.PSUChannelHistory.keys())[counter])
DifferingTimestamps.append(timestamp,sorted(TkStatusFromQuery.PSUChannelHistory.keys())[counter])
counter=counter+1
if DifferingTimestamps:
print("There are %s timestamps that are different in the 2 TkVoltageStatus objects!"%len(DifferingTimestamps))
#Test issue with channel000 and channel001 lagging:
#LVChannelsHistory={}
#for timestamp in sorted(TkStatus.PSUChannelHistory.keys()):
# LVOFF=[psuchannel for psuchannel in TkStatus.getPSUChannelsOff(timestamp) if (psuchannel.endswith('0') or psuchannel.endswith('1'))]
# for channel in LVOFF:
LVChannelHistory={}
HVChannelHistory={}
for interval in QueryResults.keys():
for row in QueryResults[interval]:
if row['dpname'].endswith('0') or row['dpname'].endswith('1'):
if row['dpname'][:-1] not in LVChannelHistory.keys():
LVChannelHistory.update({row['dpname'][:-1]:[(row['change_date'],row['actual_status'])]})
else:
LVChannelHistory[row['dpname'][:-1]].append((row['change_date'],row['actual_status']))
else:
if row['dpname'] not in HVChannelHistory.keys():
HVChannelHistory.update({row['dpname']:[(row['change_date'],row['actual_status'])]})
else:
HVChannelHistory[row['dpname']].append((row['change_date'],row['actual_status']))
#if row['change_date']==datetime.datetime(2010, 8, 28, 22, 52, 8, 994000):
# print row
#if row['change_date']==datetime.datetime(2010, 8, 28, 22, 51, 8, 994000):
# print row
if row['change_date']>datetime.datetime(2010, 8, 28, 22, 44) and row['change_date']<datetime.datetime(2010, 8, 28, 23, 5,37):
print(row)
for row in sorted(HVChannelHistory['cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_6/branchController02/easyCrate3/easyBoard15/channel002']):
print(row[0],row[1])
for row in sorted(HVChannelHistory['cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_6/branchController02/easyCrate3/easyBoard15/channel003']):
print(row[0],row[1])
print(TkStatus.PSUChannelHistory[sorted(TkStatus.PSUChannelHistory.keys())[sorted(TkStatus.PSUChannelHistory.keys()).index(datetime.datetime(2010, 8, 28, 22, 52, 8, 994000))-1]])
a=TkStatus.getIOV(datetime.datetime(2010, 8, 28, 22, 51, 16),TkStatus.PSUChannelHistory)
#PLOTTTING!
import array, time
TOBminus_1_3_1_4_HV1_Status=HVChannelHistory['cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_6/branchController02/easyCrate3/easyBoard15/channel002']
#Select time range via:
TOBminus_1_3_1_4_HV1_Status=[item for item in HVChannelHistory['cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_6/branchController02/easyCrate3/easyBoard15/channel002'] if item[0]>datetime.datetime(2010,8,28,22) and item[0]<datetime.datetime(2010,8,29,2)]
TOBTimestamps=[]
TOBHVStatus=[]
for item in TOBminus_1_3_1_4_HV1_Status:
timestamp=int(time.mktime(item[0].timetuple()))
if item==TOBminus_1_3_1_4_HV1_Status[0]: #First item does not need duplication
TOBTimestamps.append(timestamp)
HVStatus=int(item[1]==1)
TOBHVStatus.append(HVStatus)
else: #Add twice each timestamp except the first one (to make a histogram looking graph)
TOBTimestamps.append(timestamp)
TOBHVStatus.append(HVStatus) #Input previous value with new timestamp
HVStatus=int(item[1]==1)
TOBTimestamps.append(timestamp)
TOBHVStatus.append(HVStatus) #Input new value with new timestamp
#TOBTimestamps=map(lambda x: int(time.mktime(x[0].timetuple())),TOBminus_1_3_1_4_HV1_Status)
#TOBHVStatus=map(lambda y: int(y[1]==1),TOBminus_1_3_1_4_HV1_Status)
##print "FIRST the original arrays:"
###Duplication of timestamps...
##for timestamp in [item[0] for item in TOBminus_1_3_1_4_HV1_Status]:
## print timestamp,TOBHVStatus[TOBTimestamps.index(timestamp)]
## TOBTimestamps.insert(TOBTimestamps.index(timestamp)+1,timestamp)
## TOBHVStatus.insert(TOBTimestamps.index(timestamp)+1,TOBHVStatus[TOBTimestamps.index(timestamp)-1])
##print 'NOW "duplicated" arrays'
##for timestamp in TOBTimestamps:
## print timestamp, TOBHVStatus[TOBTimestamps.index(timestamp)]
##
TOBTimestampsArray=array.array('i',TOBTimestamps)
TOBHVStatusArray=array.array('i',TOBHVStatus)
TkStatus.plotGraphSeconds(TOBTimestampsArray,TOBHVStatusArray,GraphTitle="PSUChannelGraph",YTitle="Channel HV Status",GraphFilename="PSUChannel.gif")
TOBminus_1_3_1_4_HV1_Status=HVChannelHistory['cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_6/branchController02/easyCrate3/easyBoard15/channel003']
#Select time range via:
TOBminus_1_3_1_4_HV1_Status=[item for item in HVChannelHistory['cms_trk_dcs_04:CAEN/CMS_TRACKER_SY1527_6/branchController02/easyCrate3/easyBoard15/channel003'] if item[0]>datetime.datetime(2010,8,28,22) and item[0]<datetime.datetime(2010,8,29,2)]
TOBTimestamps=[]
TOBHVStatus=[]
for item in TOBminus_1_3_1_4_HV1_Status:
timestamp=int(time.mktime(item[0].timetuple()))
if item==TOBminus_1_3_1_4_HV1_Status[0]: #First item does not need duplication
TOBTimestamps.append(timestamp)
HVStatus=int(item[1]==1)
TOBHVStatus.append(HVStatus)
else: #Add twice each timestamp except the first one (to make a histogram looking graph)
TOBTimestamps.append(timestamp)
TOBHVStatus.append(HVStatus) #Input previous value with new timestamp
HVStatus=int(item[1]==1)
TOBTimestamps.append(timestamp)
TOBHVStatus.append(HVStatus) #Input new value with new timestamp
#TOBTimestamps=map(lambda x: int(time.mktime(x[0].timetuple())),TOBminus_1_3_1_4_HV1_Status)
#TOBHVStatus=map(lambda y: int(y[1]==1),TOBminus_1_3_1_4_HV1_Status)
##print "FIRST the original arrays:"
###Duplication of timestamps...
##for timestamp in [item[0] for item in TOBminus_1_3_1_4_HV1_Status]:
## print timestamp,TOBHVStatus[TOBTimestamps.index(timestamp)]
## TOBTimestamps.insert(TOBTimestamps.index(timestamp)+1,timestamp)
## TOBHVStatus.insert(TOBTimestamps.index(timestamp)+1,TOBHVStatus[TOBTimestamps.index(timestamp)-1])
##print 'NOW "duplicated" arrays'
##for timestamp in TOBTimestamps:
## print timestamp, TOBHVStatus[TOBTimestamps.index(timestamp)]
##
TOBTimestampsArray=array.array('i',TOBTimestamps)
TOBHVStatusArray=array.array('i',TOBHVStatus)
TkStatus.plotGraphSeconds(TOBTimestampsArray,TOBHVStatusArray,GraphTitle="PSUChannelGraph",YTitle="Channel HV Status",GraphFilename="PSUChannelHV2.gif")
def plotPSUChannelvsTime(self,TimeArray,ValuesArray,GraphTitle="PSUChannelGraph",YTitle="Channel HV Status",GraphFilename="PSUChannel.gif"):
"""
Function that given an array with timestamps (massaged to introduce a second timestamp for each value to produce an histogram-looking plot) and a corresponding array with values to be plotted, a title, a Y axis title and a plot filename, produces with pyROOT a time plot and saves it locally.
The function can be used for cumulative plots (number of channels with HV/LV OFF/ON vs time) or for individual (single detID HV/LV status vs time) plots.
"""
import ROOT
canvas=ROOT.TCanvas()
graph=ROOT.TGraph(len(TimeArray),TimeArray,ValuesArray)
graph.GetXaxis().SetTimeDisplay(1)
graph.GetXaxis().SetLabelOffset(0.02)
#Set the time format for the X Axis labels depending on the total time interval of the plot!
TotalTimeIntervalSecs=TimeArray[-1]-TimeArray[0]
if TotalTimeIntervalSecs <= 120: #When zooming into less than 2 mins total interval report seconds too
graph.GetXaxis().SetTimeFormat("#splitline{ %d/%m}{%H:%M:%S}")
elif 120 < TotalTimeIntervalSecs < 6400: #When zooming into less than 2 hrs total interval report minutes too
graph.GetXaxis().SetTimeFormat("#splitline{%d/%m}{%H:%M}")
else: #When plotting more than 2 hrs only report the date and hour of day
graph.GetXaxis().SetTimeFormat("#splitline{%d/%m}{ %H}")
graph.GetYaxis().SetTitle(YTitle)
graph.GetYaxis().SetTitleOffset(1.4)
graph.SetTitle(GraphTitle)
graph.Draw("APL")
canvas.SaveAs(GraphFilename)
print("Saved graph as %s"%GraphFilename)
return
ReducedIOVsTimestampsTEST=TkStatus.getReducedIOVs(datetime.datetime(2010, 8, 27, 12, 0),datetime.datetime(2010, 8, 29, 17, 45),TkStatus.PSUChannelHistory,2,90)
#Print out for debugging the reduced timestamps with their index (to see when a sequence is present) and the number of LV/HV channels OFF for the given timestamp in the TkStatus object!
print("Dumping ReducedIOVsTimestamps and the corresponding timestamp index and number of HV/LV channels off:")
for timestamp in ReducedIOVsTimestampsTEST:
TkStatus.debug=False
print(timestamp,sorted(TkStatus.PSUChannelHistory.keys()).index(timestamp),len(TkStatus.getDetIDsHVOff(timestamp)[0]), len(TkStatus.getDetIDsLVOff(timestamp)[0]))
ValidationReducedIOVsHistoryTEST=ReducedIOVsHistory(ReducedIOVsTimestampsTEST)
print("Dumping ValidationReducedIOVsHistory contents:")
for timestamp in sorted(ValidationReducedIOVsHistoryTEST.keys()):
print(timestamp, len(ValidationReducedIOVsHistoryTEST[timestamp][0]),len(ValidationReducedIOVsHistoryTEST[timestamp][1]))#,sorted(O2OReducedIOVs.keys())[i],len(O2OReducedIOVs[sorted(O2OReducedIOVs.keys())[i]][0]),len(O2OR
|