APDHVSetting.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-2-999-999-999'
37  locationToAPD = dict( keyval = ( 'stupidapd', (-999, -999, 999., -999, now), ('stupidfeb', -999, now, -999., -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 from block/plane/module to diblock/dcm/feb port
49  SQL = "select CAST(btrim(fcom.location1, 'DIBLK:') AS INT) diblk, CAST(btrim(fcom.position1, 'DCM:') AS INT) dcm , CAST(btrim(fcom.port1,'PRT:') AS INT) feb, mod.block, mod.layer, mod.position_in_layer from fnalprod_public.feb_comm_cables fcom, module mod, barcoded_item bi where mod.barcoded_item_id={} and (mod.block=CAST(btrim(fcom.location2,'BLK:') AS INT) and mod.layer=CAST(btrim(fcom.position2,'PLN:') AS INT) and mod.position_in_layer=CAST(btrim(fcom.port2,'POS:') AS INT)) and bi.barcoded_item_id={} ORDER BY diblk ASC, dcm ASC, feb ASC".format(mod,apdinfo[3])
50  curAR.execute(SQL)
51  loc = curAR.fetchone()
52  location = (loc[0], loc[1], loc[2])
53  keyval = "dcm-2-{}-{}-{}".format(loc[0], loc[1], loc[2])
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-2-{}-{} port {} assigned twice: \n".format(location[0], location[1], location[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[4] > prevAPDInfo[4] :
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  diblock = '{}'.format(location[0])
117  if location[0] < 10 : diblock = '0{}'.format(location[0])
118  dcmposition = '{}'.format(location[1])
119  if location[1] < 10 : dcmposition = '0{}'.format(location[1])
120  temp = "warm"
121  if apdinfo[1] < 0 : temp = "cold"
122 
123  dcmloc = 'dcm-2-{}-{}'.format(diblock, dcmposition)
124 
125  if dcm in dcmloc :
126  settingInfo = '1,{},{},{},{},2,0,0,0,0\n'.format(dcmloc, location[2], temp, round(voltage) )
127  locInfo = '{},{},{},{}\n'.format(dcmloc, location[2], apd, apdinfo[4])
128  settingFile.write(settingInfo)
129  locFile.write(locInfo)
130 
131  # close the files.
132  settingFile.close()
133  locFile.close()
134 
135 
136 #read in the password for the db
137 pswdloc = os.environ['NOVADBPWDFILE']
138 pswdfile = open(pswdloc, "r")
139 pswd = pswdfile.read()
140 
141 SQL = "dbname=nova_hardware host=ifdbprod.fnal.gov user=nova_reader password={} port=5432".format(pswd)
142 
143 # set up the argument parser, --safe tells the program to make the safe voltage files
144 parser = argparse.ArgumentParser()
145 parser.add_argument("--safe", help="set voltages 30V below nominal", action="store_true")
146 parser.add_argument("--dcm", help="specify which dcm to set the HV for, e.g. dcm-2-01", default="dcm-2")
147 args = parser.parse_args()
148 useSafeMode = args.safe
149 dcm = args.dcm
150 
151 if useSafeMode : print "HV will be set in safe mode for {}".format(dcm)
152 else : print "HV will be set for {}".format(dcm)
153 
154 # try connecting to the database
155 # use the Fermilab (FL) database for testing information and the Ash River (AR)
156 # for the most up-to-date installation information
157 try:
158  connFL = psycopg2.connect(SQL)
159 except:
160  print "Unable to connect to the FL database"
161  exit(0)
162 try:
163  SQL = "dbname=novaqa host=198.124.69.52 user=nova_reader password={} port=5432".format(pswd)
164  connAR = psycopg2.connect(SQL)
165 except:
166  print "Unable to connect to the AR database"
167  exit(0)
168 
169 curFL = connFL.cursor()
170 curAR = connAR.cursor()
171 
172 SQL = "set search_path to ashriverprod_factory;"
173 curFL.execute(SQL)
174 SQL = "set search_path to nova;"
175 curAR.execute(SQL)
176 
177 # file to store debug/error information
178 debugName = "debuginfo.txt"
179 debugFile = open(debugName, "w")
180 
181 # have to be sure we are only looking at APDs and FEBs from the far detector. Use
182 # the Hardware_position database to make dictionaries for the FEBs and APDs
183 dummy = 'dummyhw'
184 nonFDHW = dict(dummy = (dummy, dummy))
185 SQL = "select hw_id, hw_type, detector from public.Hardware_position where hw_type='FEB' OR hw_type='APD'"
186 curFL.execute(SQL)
187 rows = curFL.fetchall()
188 for row in rows:
189  hw_type = str(row[1])
190  if hw_type == 'APD' :
191  chars = len(row[0])
192  sn = row[0][chars-7:]
193  elif hw_type == 'FEB' :
194  feb = str(row[0])
195  febsn1 = feb.replace('_', '.')
196  sn = febsn1.replace('-', '.')
197 
198  nonFDHW[sn] = hw_type, str(row[2])
199 
200 # get the feb slope and intercept information
201 # using a csv file for now, change to the database when available.
202 dummy = 'dummyfeb'
203 febinfo = dict(dummy = (-999., -999.))
204 
205 SQL = "select febtest.febsn, febtest.hvfitintercept, febtest.hvfitslope from public.feb_test_summary febtest"
206 curFL.execute(SQL)
207 rows = curFL.fetchall()
208 
209 for row in rows:
210  feb = str(row[0])
211  # change the format of the SN from having "_" or "-" to "." instead to be consistent with the db
212  febsn1 = feb.replace('_', '.')
213  febsn = febsn1.replace('-', '.')
214  # just put the last entry for the feb into the dictionary
215  if febsn not in nonFDHW :
216  febinfo[febsn] = float(row[1]), float(row[2])
217 
218 # get the relevant information from the APD table
219 # create a separate dictionary for each temperature range, > 0 and < 0
220 # if the current APD serial number exists in the dictionary, check the
221 # batch number and take the highest and overwrite the current entry if necessary
222 SQL = "select astat.apd_id, astat.batch_no, astat.target_degc, astat.Vr from public.apd_stats astat"
223 curFL.execute(SQL)
224 rows = curFL.fetchall()
225 dummy = 'dummyapd1'
226 apdStatsLowT = dict(dummy = (-999, -999, 999.) )
227 apdStatsHighT = dict(dummy = (-999, 999, 999.) )
228 for row in rows:
229  # grab the last 7 characters of the apd SN only
230  # first determine how many characters are in the string
231  # then only keep the last 7
232  chars = len(row[0])
233  apd = row[0][chars-7:]
234  batch = row[1]
235  temp = row[2]
236  vr = row[3]
237  stats = (batch, temp, vr)
238 
239  # decide which temperature we are looking at
240  # and also use the most recent test
241  if apd not in nonFDHW :
242  if temp > 0:
243  if apd not in apdStatsHighT:
244  apdStatsHighT[apd] = stats
245  else :
246  prevStats = apdStatsHighT.get(apd)
247  prevBatch = prevStats[0]
248  if batch > prevBatch:
249  apdStatsHighT[apd] = stats
250  else:
251  if apd not in apdStatsLowT:
252  apdStatsLowT[apd] = stats
253  else :
254  prevStats = apdStatsLowT.get(apd)
255  prevBatch = prevStats[0]
256  if batch > prevBatch:
257  apdStatsLowT[apd] = stats
258 
259 # now have all the APDs, go through and query for the FEB each is attached to
260 # first do a query to get all the installed APD serial numbers
261 SQL = "select bi.barcoded_item_id, bi.barcode, bi.date_added from barcoded_item bi where bi.glassfish_discriminator='apd' and date_removed is NULL"
262 curAR.execute(SQL)
263 rows = curAR.fetchall()
264 now = time.localtime()
265 # dictionary has (apdinfo, barcode, added date), (feb SN, barcode, added date, intercept, slope), module barcode
266 apdToFEBLowT = dict(dummy = ((-999, -999, 999., -999, now), ('stupidfeb', -999, now, -999., -999), -999))
267 apdToFEBHighT = dict(dummy = ((-999, -999, 999., -999, now), ('stupidfeb', -999, now, -999., -999), -999))
268 
269 # loop over the rows returned by the query
270 for row in rows:
271  chars = len(row[1])
272  apd = row[1][chars-7:]
273  bcid = row[0]
274  apdadded = row[2]
275 
276  # now grab the module connection information for the apd
277  # if the apd is connected to 0 modules just skip it and
278  # go to the next one in the list
279  # the query ignores any entry where the nova connection entry removed date is not null
280  # if the apd is connected to multiple modules, then check
281  # if they are duplicates. if they are not, skip this apd
282  SQL = 'select mac.module, mac.connection_id, nc.date_removed from module_apd_connection mac, nova_connection nc where mac.apd={} and nc.connection_id=mac.connection_id and nc.date_removed is NULL;'.format(bcid)
283  curAR.execute(SQL)
284  numrows = curAR.rowcount
285 
286  if numrows < 1 :
287  continue
288 
289  apdcon = curAR.fetchone()
290  mod = apdcon[0]
291  modcon = apdcon[1]
292 
293  if numrows > 1 :
294  debugFile.write('APD {} {} appears to be connected to multiple modules, it will be skipped\n'.format(apd, bcid))
295  macrows = curAR.fetchall()
296  debugFile.write('\t The following connections are still valid:\n')
297  for macrow in macrows :
298  debugFile.write('\t\t Module ID {}, Connection ID {}\n'.format(macrow[0], macrow[1]))
299  continue
300 
301  # grab the feb connected to the module
302  SQL = 'select bi.barcode, mfc.feb, bi.barcoded_item_id, bi.date_added, mfc.connection_id, mfc.module, nc.date_removed from barcoded_item bi, module_feb_connection mfc, nova_connection nc where mfc.module={} and bi.barcoded_item_id=mfc.feb and nc.connection_id=mfc.connection_id and nc.date_removed is NULL;'.format(mod)
303  curAR.execute(SQL)
304  numrows = curAR.rowcount
305 
306  # if the feb is not connected to a module, just go to the next apd
307  if numrows < 1 :
308  debugFile.write('Module {} is not connected to a feb for APD {} \n'.format(mod,apd))
309  continue
310 
311  # if a module has multiple febs, assume the last one added is still there
312  febcon = curAR.fetchone()
313  febsn = str(febcon[0])
314  modcon = febcon[4]
315  added = febcon[3]
316 
317  if numrows > 1 :
318  debugFile.write('Module {} appears to be connected to multiple febs\n'.format(mod))
319  febrows = curAR.fetchall()
320  debugFile.write('\t The following connections are still valid:\n')
321  prevDate = added
322  for febrow in febrows :
323  debugFile.write('\t\t Module ID {}, Connection ID {} added on {}\n'.format(febrow[5], febrow[4], febrow[3]))
324  if febrow[3] > prevDate :
325  modcon = febrow[4]
326  removed = febrow[6]
327  prevDate = febrow[3]
328  febsn = str(febrow[0])
329  added = febrow[3]
330  debugFile.write('\t using connection {} for added date of {}, removed date {}.\n'.format(modcon, added, removed))
331 
332  # look for the feb in the febinfo dictionary
333  if febsn in febinfo :
334  febmb = febinfo.get(febsn)
335  febdata = (febsn, febcon[1], added, febmb[0], febmb[1])
336  else :
337  debugFile.write('FEB {} installed but slope and intercept information not in database, use average values\n'.format(febsn))
338  febdata = (febsn, febcon[1], added, 293.53, 0.02586)
339  #exit()
340 
341  # now connect the FEB SN to the apd info
342  # find the apd in the apdInfo dictionary
343  if apd in apdStatsLowT :
344  apdstats = apdStatsLowT.get(apd)
345  apdinfo = (apdstats[0], apdstats[1], apdstats[2], bcid, apdadded)
346  apdToFEBLowT[apd] = (apdinfo, febdata, mod)
347  if apd in apdStatsHighT :
348  apdstats = apdStatsHighT.get(apd)
349  apdinfo = (apdstats[0], apdstats[1], apdstats[2], bcid, apdadded)
350  apdToFEBHighT[apd] = (apdinfo, febdata, mod)
351 
352 settings(apdToFEBHighT, "HighT")
353 settings(apdToFEBLowT, "LowT")
354 
355 debugFile.close()
356 
357 if(useSafeMode) :
358  print "Finished making safe APD HV settings files"
359 else :
360  print "Finished making nominal APD HV settings files"
fvar< T > round(const fvar< T > &x)
Definition: round.hpp:23
if(dump)
def settings(apddict, filesuffix)
Definition: APDHVSetting.py:13
std::string format(const int32_t &value, const int &ndigits=8)
Definition: HexUtils.cpp:14
procfile open("FD_BRL_v0.txt")
exit(0)