NDAPDHVSetting.py
Go to the documentation of this file.
1 import psycopg2
2 import csv
3 import datetime
4 import time
5 import argparse
6 import os
7 
8 # This function does the final step of writing the output file for the different temperature
9 # settings of each apd used in the detector
10 # apddict is a dictionary that maps APD serial number to the feb it is connected to
11 # and the module it is mounted on. There is a dictionary for each temperature setting
12 # filesuffix is the identifier for low or high temperature running
13 def settings(apddict, filesuffix) :
14 
15  fileName = "hv_"+filesuffix+".csv"
16  if(useSafeMode) :
17  fileName = "hv_Safe"+filesuffix+".csv"
18  settingFile = open(fileName, "w")
19  fileName = "apd_installation.txt"
20  locFile = open(fileName, "w")
21 
22  default = '1,default,-1,cold,1000.0,0,1,2,3,4\n'
23  scaleFactor = 1.
24 
25  # according to Leon M, warm voltages should be 0.976 the value recorded because we
26  # operate at 15C, not the warm test value of 25C
27  if(filesuffix == "HighT") :
28  default = '1,default,-1,warm,2000.0,0,1,2,3,4\n'
29  scaleFactor = 0.976
30 
31  # put in the default line
32  settingFile.write(default)
33 
34  # make a dictionary of apd to location on the detector
35  # additional information is diblock, dcm, febport, then voltage
36  keyval = 'dcm-1-999-999-999'
37  locationToAPD = dict( keyval = ( 'stupidapd', (-999, -999, 999., now), ('stupidfeb', -999, now, -999., -999), -999, (-999, -999), -999.))
38 
39  # loop over the apds
40  for apd in apddict.iterkeys():
41  data = apddict.get(apd)
42  apdinfo = data[0]
43  febdata = data[1]
44  mod = data[2]
45 
46  if(apdinfo[0] == -999) : continue
47 
48  # grab the location information for the apd diblock/dcm/feb port
49  SQL = "SELECT dcm_name, dcm_port FROM hardware_position WHERE remove_date IS NULL AND RIGHT(hw_id,7) = \'{}\'".format(apd)
50  curAR.execute(SQL)
51  loc = curAR.fetchone()
52  location = (loc[0], loc[1])
53  keyval = "{}-{}".format(loc[0], loc[1])
54 
55  # have all the pieces we need now
56  # - apd voltage and location in apdinfo
57  # - feb to apd connection in febtoapd
58  # - feb voltage slope and intercept, remember abscisa is 4095 steps
59  # find nearest integer to (apdinfo[2] - febdata[3])/febdata[4]
60  # 1,<dcmName>,<febId>,<coolingState>,<voltage>,2,0,0,0,0
61  intercept = febdata[3]
62  slope = febdata[4]
63  if slope == 0. :
64  slope = 0.02586
65 
66  voltage = (scaleFactor*apdinfo[2] - intercept)/slope
67  if(useSafeMode) :
68  voltage = (apdinfo[2] - 30 - intercept)/slope
69 
70  #voltage = (350 - intercept)/slope
71 
72  # test the voltage setting
73  if apdinfo[1] > 0 and (voltage < 2500 or voltage > 4094) :
74  #print "Setting for loc: {} with APD: {} at temp {} is out of range {}".format(keyval, apd, apdinfo[1], voltage)
75  if voltage > 4094: voltage = 4094
76  elif voltage < 2500: voltage = 2500
77  elif apdinfo[1] < 0 and (voltage < 1000 or voltage > 4000) :
78  #print "Setting for loc: {} with APD: {} at temp {} is out of range {}".format(keyval, apd, apdinfo[1], voltage)
79  if voltage > 4000: voltage = 4000
80  elif voltage < 1000: voltage = 1000
81 
82  # check to see if the electronics location has already been used. If not, then
83  # insert it into the dictionary. If it has been used, then make sure the most
84  # recent entry is in the dictionary
85  if keyval not in locationToAPD :
86  locationToAPD[keyval] = (apd, apdinfo, febdata, mod, location, voltage)
87  else :
88  data = locationToAPD.get(keyval)
89  prevAPD = data[0]
90  prevAPDInfo = data[1]
91  prevFEB = data[2]
92  # debugFile.write("dcm-1-{}-{} port {} assigned twice: \n".format(location[0]))#, loc[1]))# loc[2]))
93  debugFile.write("\t Currently assigned APD: {} {} {}\n".format(prevAPD, prevAPDInfo, prevFEB))
94  debugFile.write("\t Alternate assigned APD: {} {} {}\n".format(apd, apdinfo, febdata))
95  if apdinfo[3] > prevAPDInfo[3] :
96  locationToAPD[keyval] = (apd, apdinfo, febdata, mod, location, voltage)
97  debugFile.write("\t\t Using APD: {} {} {}\n".format(apd, apdinfo, febdata))
98  else :
99  debugFile.write("\t\t Using APD: {} {} {}\n".format(prevAPD, prevAPDInfo, prevFEB))
100 
101  # loop over all electronics locations in the dictionary and
102  # and write them out to the file. Also write out the location used
103  # and the relevant information about the APD installed there
104  for keyval in locationToAPD :
105 
106  data = locationToAPD.get(keyval)
107  apd = data[0]
108  apdinfo = data[1]
109  febdata = data[2]
110  mod = data[3]
111  location = data[4]
112  voltage = data[5]
113 
114  if location[0] == -999 : continue
115 
116  dcmloc = location[0]
117 
118  temp = "warm"
119  if apdinfo[1] < 0 : temp = "cold"
120 
121  if dcm in dcmloc :
122  settingInfo = '1,{},{},{},{},2,0,0,0,0\n'.format(dcmloc, location[1], temp, round(voltage) )
123  locInfo = '{},{},{},{}\n'.format(dcmloc, location[1], apd, apdinfo[3])
124  settingFile.write(settingInfo)
125  locFile.write(locInfo)
126 
127  # close the files.
128  settingFile.close()
129  locFile.close()
130 
131 
132 #read in the password for the db
133 pswdloc = os.environ['NOVADBPWDFILE']
134 pswdfile = open(pswdloc, "r")
135 pswd = pswdfile.read()
136 
137 SQL = "dbname=nova_hardware host=ifdbprod.fnal.gov user=nova_reader password={} port=5432".format(pswd)
138 
139 # try connecting to the database
140 # use the Fermilab (FL) database for testing information and the Ash River (AR)
141 # for the most up-to-date installation information
142 try:
143  connFL = psycopg2.connect(SQL)
144 except:
145  print "Unable to connect to the FL database"
146  exit(0)
147 try:
148  SQL = "dbname=nova_hardware host=ifdbprod user=nova_reader password={} port=5432".format(pswd)
149  connAR = psycopg2.connect(SQL)
150 except:
151  print "Unable to connect to the AR database"
152  exit(0)
153 
154 # set up the argument parser, --safe tells the program to make the safe voltage files
155 parser = argparse.ArgumentParser()
156 parser.add_argument("--safe", help="set voltages 30V below nominal", action="store_true")
157 parser.add_argument("--dcm", help="specify which dcm to set the HV for, e.g. dcm-2-01", default="dcm-1")
158 args = parser.parse_args()
159 useSafeMode = args.safe
160 dcm = args.dcm
161 
162 #if useSafeMode : print "HV will be set in safe mode for {}".format(dcm)
163 #else : print "HV will be set for {}".format(dcm)
164 
165 curFL = connFL.cursor()
166 curAR = connAR.cursor()
167 
168 SQL = "set search_path to ashriverprod_factory;"
169 curFL.execute(SQL)
170 SQL = "set search_path to public;"
171 curAR.execute(SQL)
172 
173 # file to store debug/error information
174 debugName = "debuginfo.txt"
175 debugFile = open(debugName, "w")
176 
177 # get the feb slope and intercept information
178 # using a csv file for now, change to the database when available.
179 dummy = 'dummyfeb'
180 febinfo = dict(dummy = (-999., -999.))
181 
182 SQL = "select febtest.febsn, febtest.hvfitintercept, febtest.hvfitslope from public.feb_test_summary febtest"
183 curFL.execute(SQL)
184 rows = curFL.fetchall()
185 
186 for row in rows:
187  feb = str(row[0])
188  # change the format of the SN from having "_" or "-" to "." instead to be consistent with the db
189  febsn1 = feb.replace('_', '.')
190  febsn = febsn1.replace('-', '.')
191  # just put the last entry for the feb into the dictionary
192  febinfo[febsn] = float(row[1]), float(row[2])
193 
194 # get the relevant information from the APD table
195 # create a separate dictionary for each temperature range, > 0 and < 0
196 # if the current APD serial number exists in the dictionary, check the
197 # batch number and take the highest and overwrite the current entry if necessary
198 SQL = "select astat.apd_id, astat.batch_no, astat.target_degc, astat.Vr from public.apd_stats astat"
199 curFL.execute(SQL)
200 rows = curFL.fetchall()
201 dummy = 'dummyapd1'
202 apdStatsLowT = dict(dummy = (-999, -999, 999.) )
203 apdStatsHighT = dict(dummy = (-999, 999, 999.) )
204 for row in rows:
205  # grab the last 7 characters of the apd SN only
206  # first determine how many characters are in the string
207  # then only keep the last 7
208  chars = len(row[0])
209  apd = row[0][chars-7:]
210  batch = row[1]
211  temp = row[2]
212  vr = row[3]
213  stats = (batch, temp, vr)
214 
215  # decide which temperature we are looking at
216  # and also use the most recent test
217  if temp > 0:
218  if apd not in apdStatsHighT:
219  apdStatsHighT[apd] = stats
220  else :
221  prevStats = apdStatsHighT.get(apd)
222  prevBatch = prevStats[0]
223  if batch > prevBatch:
224  apdStatsHighT[apd] = stats
225  else:
226  if apd not in apdStatsLowT:
227  apdStatsLowT[apd] = stats
228  else :
229  prevStats = apdStatsLowT.get(apd)
230  prevBatch = prevStats[0]
231  if batch > prevBatch:
232  apdStatsLowT[apd] = stats
233 
234 # now have all the APDs, go through and query for the FEB each is attached to
235 # first do a query to get all the installed APD serial numbers
236 SQL = "SELECT hw_id, install_date FROM hardware_position WHERE hw_type = \'{}\' AND remove_date is NULL AND detector = \'{}\'".format("APD","NearDet")
237 curAR.execute(SQL)
238 rows = curAR.fetchall()
239 now = time.localtime()
240 # dictionary has (apdinfo, barcode, added date), (feb SN, barcode, added date, intercept, slope), module barcode
241 apdToFEBLowT = dict(dummy = ((-999, -999, 999., now), ('stupidfeb', -999, now, -999., -999), -999))
242 apdToFEBHighT = dict(dummy = ((-999, -999, 999., now), ('stupidfeb', -999, now, -999., -999), -999))
243 
244 # loop over the rows returned by the query
245 for row in rows:
246  chars = len(row[0])
247  apd = row[0][chars-7:]
248  apdadded = row[1]
249 
250  # now grab the module connection information for the apd
251  # if the apd is connected to 0 modules just skip it and
252  # go to the next one in the list
253  # the query ignores any entry where the nova connection entry removed date is not null
254  # if the apd is connected to multiple modules, then check
255  # if they are duplicates. if they are not, skip this apd
256  SQL = "SELECT block, plane, module_position FROM hardware_position WHERE hw_type =\'{}\' AND remove_date is NULL AND RIGHT(hw_id,7) = \'{}\' AND detector = \'{}\'".format("APD",apd,"NearDet")
257  curAR.execute(SQL)
258  numrows = curAR.rowcount
259 
260  if numrows < 1 :
261  continue
262 
263  apdcon = curAR.fetchone()
264  block = apdcon[0]
265  plane = apdcon[1]
266  modpos = apdcon[2]
267 
268  mod = "{} on plane {} in block {}".format(modpos,plane,block)
269 
270  if numrows > 1 :
271  debugFile.write('APD {} appears to be connected to multiple modules, it will be skipped\n'.format(apd))
272  macrows = curAR.fetchall()
273  debugFile.write('\t The following connections are still valid:\n')
274  for macrow in macrows :
275  debugFile.write('\t\t Module {}, Plane {}, Block {}\n'.format(macrow[2], macrow[1], macrow[0]))
276  continue
277 
278  # grab the feb connected to the module
279  SQL = "SELECT hw_id, block, plane, module_position, install_date FROM hardware_position WHERE hw_type = \'{}\' AND remove_date IS NULL AND block = \'{}\' and plane = \'{}\' and module_position = \'{}\' AND detector = \'{}\'".format("FEB",block,plane,modpos, "NearDet")
280 
281  curAR.execute(SQL)
282  numrows = curAR.rowcount
283 
284  # if the feb is not connected to a module, just go to the next apd
285  if numrows < 1 :
286  debugFile.write('Module {} is not connected to a feb\n'.format(mod))
287  continue
288 
289  # if a module has multiple febs, assume the last one added is still there
290  febcon = curAR.fetchone()
291  febsn = str(febcon[0])
292  febblock= febcon[1]
293  febplane= febcon[2]
294  febpos = febcon[3]
295  added = febcon[4]
296 
297  if numrows > 1 :
298  debugFile.write('Module {} appears to be connected to multiple febs\n'.format(mod))
299  febrows = curAR.fetchall()
300  debugFile.write('\t The following connections are still valid:\n')
301  prevDate = added
302  for febrow in febrows :
303  debugFile.write('\t\t FEB {} on Module {}, Block {}, Plane {} added on {}\n'.format(febrow[0],febrow[3], febrow[1], febrow[2], febrow[4]))
304  if febrow[4] > prevDate :
305  febsn =str(febcon[0])
306  febblock= febcon[1]
307  febplane= febcon[2]
308  febpos = febcon[3]
309  added = febcon[4]
310  prevdate=added
311  debugFile.write('\t using FEB {} for added date of {}.\n'.format(febsn, added))
312 
313  # look for the feb in the febinfo dictionary
314  if febsn in febinfo :
315  febmb = febinfo.get(febsn)
316  febdata = (febsn, febcon[1], added, febmb[0], febmb[1])
317  else :
318  debugFile.write('FEB {} installed but slope and intercept information not in database, use average values\n'.format(febsn))
319  febdata = (febsn, febcon[1], added, 293.53, 0.02586)
320  #exit()
321 
322  # now connect the FEB SN to the apd info
323  # find the apd in the apdInfo dictionary
324  if apd in apdStatsLowT :
325  apdstats = apdStatsLowT.get(apd)
326  apdinfo = (apdstats[0], apdstats[1], apdstats[2], apdadded)
327  apdToFEBLowT[apd] = (apdinfo, febdata, mod)
328  if apd in apdStatsHighT :
329  apdstats = apdStatsHighT.get(apd)
330  apdinfo = (apdstats[0], apdstats[1], apdstats[2], apdadded)
331  apdToFEBHighT[apd] = (apdinfo, febdata, mod)
332 
333 settings(apdToFEBHighT, "HighT")
334 settings(apdToFEBLowT, "LowT")
335 
336 debugFile.close()
337 
338 if(useSafeMode) :
339  print "Finished making safe APD HV settings files"
340 else :
341  print "Finished making nominal APD HV settings files"
def settings(apddict, filesuffix)
fvar< T > round(const fvar< T > &x)
Definition: round.hpp:23
if(dump)
std::string format(const int32_t &value, const int &ndigits=8)
Definition: HexUtils.cpp:14
procfile open("FD_BRL_v0.txt")
exit(0)