This repository has been archived by the owner on Jan 31, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 20
/
ultraScurve.py
executable file
·335 lines (262 loc) · 14.5 KB
/
ultraScurve.py
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
#!/bin/env python
r"""
Scurves
=======
FIXME Add detailed description
``ultraScurve.py``
==================
Synopsis
--------
**run_scans.py** **scurve** [-**h**] [--**chMax** *CHMAX*] [--**chMin** *CHMAX*] [-**l** *LATENCY*] [-**m** *MSPL*] [-**n** *NEVTS*] [--**vfatmask** *VFATMASK*] shelf slot ohMask
Mandatory arguments
-------------------
.. program:: run_Scans.py scurve
Positional arguments
--------------------
.. option:: shelf
uTCA crate shelf number
.. option:: slot
AMC slot number in the uTCA crate
.. option:: ohMask
optohybrid mask to apply, a 1 in the n^{th} bit indicates the n^{th} OH should be considered
Optional arguments
------------------
.. option:: -h, --help
show the help message and exit
.. option:: --chMax <CHMAX>
Specify maximum channel number to scan
.. option:: --chMin <CHMIN>
Specify minimum channel number to scan
.. option:: -l, --latency <LATENCY>
Setting of ``CFG_LATENCY`` register
.. option:: -m, --mspl <MSPL>
Setting of ``CFG_PULSE_STRETCH`` register
.. option:: -n, --nevts <NEVTS>
Number of events for each scan position
.. option:: --vfatmask <VFATMASK>
If specified this will use this VFAT mask for all unmasked OHs in ohMask. Here this is a 24 bit number, where a 1 in the N^{th} bit means ignore the N^{th} VFAT. If this argument is not specified, VFAT masks are determined at runtime automatically.
Environment
-----------
The following `$SHELL` variables should be defined beforehand:
.. glossary::
:envvar: `BUILD_HOME`
the location of your ``vfatqc-python-scripts`` directory
:envvar: `DATA_PATH`
the location of input data
Then execute:
`source $BUILD_HOME/vfatqc-python-scripts/setup/paths.sh`
"""
if __name__ == '__main__':
"""
Script to take Scurve data using OH ultra scans
By: Cameron Bravo (c.bravo@cern.ch) and Brian Dorney (brian.l.dorney@cern.ch)
"""
from array import array
from ctypes import *
from gempython.tools.optohybrid_user_functions_uhal import scanmode
from gempython.tools.vfat_user_functions_xhal import *
from gempython.tools.hw_constants import vfatsPerGemVariant
from gempython.vfatqc.utils.qcoptions import parser
import os, sys
parser.add_option("--CalPhase", type="int", dest = "CalPhase", default = 0,
help="Specify CalPhase. Must be in range 0-8", metavar="CalPhase")
parser.add_option("--calSF", type="int", dest = "calSF", default = 0,
help="V3 electroncis only. Value of the CFG_CAL_FS register", metavar="calSF")
parser.add_option("--chMin", type="int", dest = "chMin", default = 0,
help="Specify minimum channel number to scan", metavar="chMin")
parser.add_option("--chMax", type="int", dest = "chMax", default = 127,
help="Specify maximum channel number to scan", metavar="chMax")
parser.add_option("-f", "--filename", type="string", dest="filename", default="SCurveData.root",
help="Specify Output Filename", metavar="filename")
parser.add_option("--L1Atime", type="int", dest = "L1Atime", default = 250,
help="Specify time between L1As in bx", metavar="L1Atime")
parser.add_option("--latency", type="int", dest = "latency", default = 37,
help="Specify Latency", metavar="latency")
parser.add_option("--mspl", type="int", dest = "MSPL", default = 3,
help="Specify MSPL. Must be in the range 0-7 (default is 3)", metavar="MSPL")
parser.add_option("--pulseDelay", type="int", dest = "pDel", default = 40,
help="Specify time of pulse before L1A in bx", metavar="pDel")
parser.add_option("--voltageStepPulse", action="store_true",dest="voltageStepPulse",
help="V3 electronics only. Calibration Module is set to use voltage step pulsing instead of default current pulse injection",
metavar="voltageStepPulse")
parser.add_option("--gemType",type=str,help="String that defines the GEM variant, available from the list: {0}".format(gemVariants.keys()),default="ge11")
parser.add_option("--detType",type=str,
help="Detector type within gemType. If gemType is 'ge11' then this should be from list {0}; if gemType is 'ge21' then this should be from list {1}; and if type is 'me0' then this should be from the list {2}".format(gemVariants['ge11'],gemVariants['ge21'],gemVariants['me0']),default="short")
(options, args) = parser.parse_args()
remainder = (options.scanmax-options.scanmin+1) % options.stepSize
if remainder != 0:
options.scanmax = options.scanmax + remainder
print "extending scanmax to: ", options.scanmax
import ROOT as r
filename = options.filename
myF = r.TFile(filename,'recreate')
import subprocess,datetime,time
startTime = datetime.datetime.now().strftime("%Y.%m.%d.%H.%M")
print startTime
Date = startTime
# Track the current pulse
isCurrentPulse = (not options.voltageStepPulse)
# Setup the output TTree
from gempython.vfatqc.utils.treeStructure import gemTreeStructure
gemData = gemTreeStructure('scurveTree','Tree Holding CMS GEM SCurve Data',scanmode.SCURVE)
gemData.setDefaults(options, int(time.time()))
# Open rpc connection to hw
from gempython.vfatqc.utils.qcutilities import getCardName, inputOptionsValid
cardName = getCardName(options.shelf,options.slot)
vfatBoard = HwVFAT(cardName, options.gtx, options.debug, options.gemType, options.detType)
print 'opened connection'
# Check options
from gempython.vfatqc.utils.confUtils import getChannelRegisters
if not inputOptionsValid(options, vfatBoard.parentOH.parentAMC.fwVersion):
exit(os.EX_USAGE)
pass
if options.scanmin not in range(256) or options.scanmax not in range(256) or not (options.scanmax > options.scanmin):
print("Invalid scan parameters specified [min,max] = [%d,%d]"%(options.scanmin,options.scanmax))
print("Scan parameters must be in range [0,255] and min < max")
exit(1)
pass
CHAN_MIN = options.chMin
CHAN_MAX = options.chMax + 1
mask = options.vfatmask
try:
# Set Trigger Source for v2b electronics
print "setting trigger source"
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
vfatBoard.parentOH.setTriggerSource(0x1)
print("OH%i: Trigger Source %i"%(vfatBoard.parentOH.link,vfatBoard.parentOH.getTriggerSource()))
# Configure TTC
print "attempting to configure TTC"
if 0 == vfatBoard.parentOH.parentAMC.configureTTC(options.pDel,options.L1Atime,options.gtx,1,0,0,True):
print "TTC configured successfully"
vfatBoard.parentOH.parentAMC.getTTCStatus(options.gtx,True)
else:
raise Exception('RPC response was non-zero, TTC configuration failed')
vfatBoard.setVFATLatencyAll(mask=options.vfatmask, lat=options.latency, debug=options.debug)
vfatBoard.setRunModeAll(mask, True, options.debug)
vfatBoard.setVFATMSPLAll(mask, options.MSPL, options.debug)
vfatBoard.setVFATCalPhaseAll(mask, 0xff >> (8 - options.CalPhase), options.debug)
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
vals = vfatBoard.readAllVFATs("CalPhase", 0x0)
calPhasevals = dict(map(lambda slotID: (slotID, bin(vals[slotID]).count("1")), range(0,vfatsPerGemVariant[options.gemType])))
vals = vfatBoard.readAllVFATs("ContReg2", 0x0)
msplvals = dict(map(lambda slotID: (slotID, (1+(vals[slotID]>>4)&0x7)),range(0,vfatsPerGemVariant[options.gemType])))
vals = vfatBoard.readAllVFATs("ContReg3", 0x0)
trimRangevals = dict(map(lambda slotID: (slotID, (0x07 & vals[slotID])),range(0,vfatsPerGemVariant[options.gemType])))
vals = vfatBoard.readAllVFATs("Latency", 0x0)
latvals = dict(map(lambda slotID: (slotID, vals[slotID]&0xff),range(0,vfatsPerGemVariant[options.gemType])))
#vfatIDvals = getAllChipIDs(ohboard, options.gtx, 0x0)
vals = vfatBoard.readAllVFATs("VThreshold1", 0x0)
vt1vals = dict(map(lambda slotID: (slotID, vals[slotID]&0xff),range(0,vfatsPerGemVariant[options.gemType])))
vals = vfatBoard.readAllVFATs("VThreshold2", 0x0)
vt2vals = dict(map(lambda slotID: (slotID, vals[slotID]&0xff),range(0,vfatsPerGemVariant[options.gemType])))
vthvals = dict(map(lambda slotID: (slotID, vt2vals[slotID]-vt1vals[slotID]),range(0,vfatsPerGemVariant[options.gemType])))
else:
vals = vfatBoard.readAllVFATs("CFG_CAL_PHI", mask)
calPhasevals = dict(map(lambda slotID: (slotID, bin(vals[slotID]).count("1")), range(0,vfatsPerGemVariant[options.gemType])))
vals = vfatBoard.readAllVFATs("CFG_PULSE_STRETCH", mask)
msplvals = dict(map(lambda slotID: (slotID, vals[slotID]),range(0,vfatsPerGemVariant[options.gemType])))
vals = vfatBoard.readAllVFATs("CFG_LATENCY", mask)
latvals = dict(map(lambda slotID: (slotID, vals[slotID]&0xff),range(0,vfatsPerGemVariant[options.gemType])))
vals = vfatBoard.readAllVFATs("CFG_THR_ARM_DAC", mask)
vthrvals = dict(map(lambda slotID: (slotID, vals[slotID]&0xff),range(0,vfatsPerGemVariant[options.gemType])))
chanRegData = getChannelRegisters(vfatBoard,mask)
vfatIDvals = vfatBoard.getAllChipIDs(mask)
pass
# Make sure no channels are receiving a cal pulse
# This needs to be done on the CTP7 otherwise it takes an hour...
print "stopping cal pulse to all channels"
vfatBoard.stopCalPulses(mask, 0, 127)
scanDataSizeVFAT = (options.scanmax-options.scanmin+1)/options.stepSize
scanDataSizeNet = scanDataSizeVFAT * vfatsPerGemVariant[options.gemType]
scanData = (c_uint32 * scanDataSizeNet)()
for chan in range(CHAN_MIN,CHAN_MAX):
print "Channel #"+str(chan)
# Determine the scanReg
scanReg = "CAL_DAC"
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
scanReg = "VCal"
# Perform the scan
if options.debug:
print("Starting scan; pulseDelay: %i; L1Atime: %i; Latency: %i"%(options.pDel, options.L1Atime, options.latency))
rpcResp = vfatBoard.parentOH.performCalibrationScan(
chan=chan,
calSF=options.calSF,
currentPulse=isCurrentPulse,
dacMax=options.scanmax,
dacMin=options.scanmin,
enableCal=True,
mask=options.vfatmask,
nevts=options.nevts,
outData=scanData,
stepSize=options.stepSize,
scanReg=scanReg)
if rpcResp != 0:
raise Exception('RPC response was non-zero, scurve for channel %i failed'%chan)
for vfat in range(0,vfatsPerGemVariant[options.gemType]):
if (mask >> vfat) & 0x1: continue
for vcalDAC in range(vfat*scanDataSizeVFAT,(vfat+1)*scanDataSizeVFAT):
try:
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
#trimDAC = (0x1f & vfatBoard.readVFAT(vfat,"VFATChannels.ChanReg%d"%(chan)))
gemData.fill(
calPhase = calPhasevals[vfat],
l1aTime = options.L1Atime,
latency = latvals[vfat],
mspl = msplvals[vfat],
Nev = options.nevts,
Nhits = int(scanData[vcalDAC] & 0xffffff),
pDel = options.pDel,
#trimDAC = trimDAC,
trimRange = trimRangevals[vfat],
vcal = int((scanData[vcalDAC] & 0xff000000) >> 24),
vfatCH = chan,
#vfatID = vfatIDvals[vfat],
vfatN = vfat,
vth = vthvals[vfat],
vth1 = vt1vals[vfat],
vth2 = vt2vals[vfat],
vthr = vt1vals[vfat]
)
else:
gemData.fill(
calPhase = calPhasevals[vfat],
isCurrentPulse = isCurrentPulse,
l1aTime = options.L1Atime,
latency = latvals[vfat],
mspl = msplvals[vfat],
Nev = (scanData[vcalDAC] & 0xffff),
Nhits = ((scanData[vcalDAC]>>16) & 0xffff),
pDel = options.pDel,
trimDAC = chanRegData[chan+vfat*128]['ARM_TRIM_AMPLITUDE'],
trimPolarity = chanRegData[chan+vfat*128]['ARM_TRIM_POLARITY'],
vcal = (options.scanmin + (vcalDAC - vfat*scanDataSizeVFAT) * options.stepSize),
vfatCH = chan,
vfatID = vfatIDvals[vfat],
vfatN = vfat,
vthr = vthrvals[vfat]
)
pass
except IndexError:
print 'Unable to index data for channel %i'%chan
print scanData[vcalDAC]
finally:
if options.debug:
print "vfat%i; vcal %i; Nev %i; Nhits %i"%(
gemData.vfatN[0],
gemData.vcal[0],
gemData.Nev[0],
gemData.Nhits[0])
pass
pass
gemData.autoSave("SaveSelf")
sys.stdout.flush()
pass
vfatBoard.parentOH.parentAMC.toggleTTCGen(options.gtx, False)
vfatBoard.setRunModeAll(mask, False, options.debug)
except Exception as e:
gemData.autoSave()
print "An exception occurred", e
finally:
myF.cd()
gemData.write()
myF.Close()