#!/bin/env python # # April 10, 2015 # # This script is used to make automatic entries into the # HDRUN e-log whenever a run is started. It is called by # the run_go script which is run by CODA. # # This works by gathering information from various sources # and writing it to a temporary HTML file that is then # inserted using the /site/ace/certified/apps/bin/logentry # utility. This utility is provided by the e-log maintainers. # It is technically a violation of our policy to require # files/programs from outside of the counting house, but # this requires outside network connectivity anyway. # # Questions regarding this script may be directed to: # # David Lawrence # davidl@jlab.org # x5567 # import os import sys import subprocess import datetime import glob from epics import caget,caput ELOGS = ['HDRUN'] ENTRYMAKERS = ['hdops'] RUN = '--unknown--' if len(sys.argv) > 1 : RUN = sys.argv[1] DAQ_HOME = os.getenv('DAQ_HOME', '/home/hdops/CDAQ/daq_dev_v0.31/daq') #-------------------------------------------------------- # GetRealDir # # Get the environment variable and find the actual directory # it refers to (resolving any symbolic links). Return a list # with the environment variable name as the first element and # the path as the second. #-------------------------------------------------------- def GetRealDir(envar): val = os.getenv(envar) if val != None : return [envar, val + ' ( → ' + os.path.realpath(val) + ' )'] else: return [envar, '-- unknown --'] #-------------------------------------------------------- # MakeHEADER_HTML # # Return string with HTML for first part of log entry #-------------------------------------------------------- def MakeHEADER_HTML(): global RUN items =[]; items.append(['Time',datetime.datetime.now().strftime('%c')]) items.append(['/gluex/raid',os.path.realpath('/gluex/raid')]) items.append( GetRealDir('CODA' ) ) items.append( GetRealDir('DAQ_HOME' ) ) items.append( GetRealDir('COOL_HOME' ) ) items.append( GetRealDir('CODA_ROL' ) ) items.append( GetRealDir('LINUXVME_LIB') ) html = '

Automated log entry for run '+ RUN + '

\n' html += '

This entry generated by the script: $Id$

\n' html += '

\n' html += '(n.b. some of the followng values come from environment variables in the hdops account. It is possible they do not reflect actual settings used!)\n' html += '\n' for (key,val) in items: html += ' \n' html += '
'+key+':'+val+'
\n' return html #-------------------------------------------------------- # HTMLBox # # Wrap the given text in an HTML box such that the text is # marked as the preformatted contents of the single cell of # the table. #-------------------------------------------------------- def HTMLBox(mylabel, mytext, bgcolor='#EEE'): # Print label and open HTML table html = '' html += '' + mylabel + '\n' html += '
\n' # This just gives a border around outside of table html += '\n' # Actual table # Print content html += '\n'; # Close HTML table html += '
\n' + mytext + '
\n' # actual table html += '
\n' # Border around table return html #-------------------------------------------------------- # MakeDAQ_HTML # # Get all DAQ values of interest and return them as # a string formatted as an HTML table #-------------------------------------------------------- def MakeDAQ_HTML(): global RUN, DAQ_HOME # Open HTML table html = '

\n' html += '

DAQ values

\n' # Look for run comments file run_comments_fname = '%s/../work/run_comments/run_%06d_info.txt' % (DAQ_HOME, int(RUN)) config_fname = '-- unknown --\n' hosts_fname = '-- unknown --\n' run_comments = '-- file not found --\n' config_file = '-- file not found --\n' coda_config = '-- unknown --\n' hosts_file = '-- file not found --\n' try: # Read in run comments file with open(run_comments_fname, "r") as myfile: run_comments = myfile.read() # Look for "CONFIG FILE::" line in run comments file for item in run_comments.split('\n'): if 'CONFIG FILE:: ' in item: config_fname = item[len('CONFIG FILE:: '):].strip() # Read in trigger/readout config file try: with open(config_fname, "r") as myfile2: config_file = myfile2.read() coda_config_dir = os.path.dirname(config_fname) coda_config = os.path.basename(coda_config_dir) hosts_fname = coda_config_dir + '/hosts' # Read in hosts file try: with open(hosts_fname, "r") as myfile3: hosts_file = myfile3.read() except: html += '

(can\'t open %s)

\n' % hosts_fname except: html += '

(can\'t open %s)

\n' % config_fname except: pass html += HTMLBox(run_comments_fname + ' (at GO)', run_comments, '#EEF') html += '
\n' html += HTMLBox(hosts_fname , hosts_file, '#EFE') html += '
\n' html += HTMLBox(config_fname , config_file, '#DDD') html += '

\n' return html #-------------------------------------------------------- # MakeDAQ_CONFIG_HTML # # Copy all files generated by ROLs containing selected # config. parameters into tables. #-------------------------------------------------------- def MakeDAQ_CONFIG_HTML(): global RUN, DAQ_HOME # Get list of files config_dir = '%s/../work/DAQ_CONFIG_OUT' % DAQ_HOME fnames = glob.glob('%s/daq_config_*.dat' % config_dir) # Open HTML table html = '

\n' html += 'Selected digitization module configuration parameters\n' # html += '\n' bgcolor = '#EEE' html += '
\n' # This just gives a border around outside of table html += '\n' # Actual table Nfiles = 0 for fname in fnames: html += '\n' if (Nfiles % 2) == 0 : html += '\n' html += '\n'; html += '
' + contents + '
\n'; html += '\n' if (Nfiles % 2) == 1 : html += '\n\n' Nfiles += 1 if (Nfiles % 2) == 1 : html += '\n' # handle odd number of files # Close HTML table html += '
\n' #fname = fname_path[len(config_dir)len('/daq_config_:] contents = '' with open(fname, 'r') as f: contents = f.read() # Print label and open HTML table # Print content # html += '
' + contents + '
\n' # actual table html += '
\n' # Border around table # html += '\n' html += '

\n' return html #-------------------------------------------------------- # MakeEPICS_TABLE # # This takes as input a list of epics variables for which # to make an HTML table and a title for the table. It is # called from MakeEPICS_HTML multiple times. #-------------------------------------------------------- def MakeEPICS_TABLE(title, vars, color='black'): # Open HTML table html = '

\n' html += '' + title + '\n' html += '
\n' # This just gives a border around outside of table html += '\n' # Actual table # Get each EPICS value and write into table for (var,units,description) in vars: val = caget(pvname=var, timeout=float(0.5)) if val == None: val = '-- N/A --' html += ' \n' html += ' \n' html += ' \n' html += ' \n' html += ' \n' html += ' \n' # Close HTML table html += '
' + var + '' + str(val) + '' + units + '' + description + '
\n' # actual table html += '
\n' # Border around table html += '

\n' return html #-------------------------------------------------------- # MakeEPICS_HTML # # Get all EPICS values of interest and return them as # a string formatted as an HTML table #-------------------------------------------------------- def MakeEPICS_HTML(): # Make list of variables and their descriptions # Each entry is a list containing: # # EPICSvar_name units description beamlinevars = [] beamlinevars.append(['MMSHLDE' , 'MeV' ,'Beam energy from model' ]) beamlinevars.append(['HALLD:p' , 'MeV' ,'Observed energy in accelerator' ]) beamlinevars.append(['IBCAD00CRCUR6' , 'nA' ,'Beam Current' ]) beamlinevars.append(['IPM5C11.VAL' , 'nA' ,'Beam Current at 5C11' ]) beamlinevars.append(['IPM5C11A.VAL' , 'nA' ,'Beam Current at 5C11A' ]) beamlinevars.append(['IPM5C11B.VAL' , 'nA' ,'Beam Current at 5C11B' ]) beamlinevars.append(['IPMAD00C.VAL' , 'nA' ,'Beam Current at AD00' ]) beamlinevars.append(['HallD-PXI:Data:I_Shunt' , 'A' ,'Solenoid Current' ]) beamlinevars.append(['HD:GONI:RADIATOR_NAME' , ' ' ,'Diamond Radiator' ]) beamlinevars.append(['HD:GONI:RADIATOR_INDEX' , ' ' ,'Index of Radiator Slot' ]) beamlinevars.append(['HD:GONI:RADIATOR_ID' , ' ' ,'Diamond ID (0 = amorphous)' ]) beamlinevars.append(['HD:CBREM:PLANE' , ' ' ,'PARA = 1, PERP = 2' ]) beamlinevars.append(['HD:CBREM:REQ_EDGE' , ' ' ,'Coherent Peak Nominal Edge Energy']) beamlinevars.append(['HD:GONI:X.RBV' , ' ' ,'Diamond Radiator X-value' ]) beamlinevars.append(['HD:GONI:Y.RBV' , ' ' ,'Diamond Radiator Y-value' ]) beamlinevars.append(['HD:GONI:ROLL.RBV' , ' ' ,'Diamond Radiator ROLL-value' ]) beamlinevars.append(['HD:GONI:PITCH.RBV' , ' ' ,'Diamond Radiator PITCH-value' ]) beamlinevars.append(['HD:GONI:YAW.RBV' , ' ' ,'Diamond Radiator YAW-value' ]) beamlinevars.append(['hd:radiator:motor.RBV' , ' ' ,'Tagger Amorphous radiator' ]) beamlinevars.append(['hd:polarimeter:motor.RBV' , ' ' ,'Polarimeter convertor' ]) beamlinevars.append(['US1-2-BOT:m2.RBV' , ' ' ,'PS convertor' ]) beamlinevars.append(['US1-2-BOT:m1.RBV' , ' ' ,'Collimator' ]) beamlinevars.append(['RESET:i:AmbUpStreamSol_Temp', 'F' ,'Temp. of Upstream Solenoid' ]) beamlinevars.append(['RESET:i:AmbDownstreamSol_Temp','F' ,'Temp. of Downstream Solenoid' ]) beamlinevars.append(['RESET:i:AmbUpstreamSol_Hum' , '%' ,'Humidity of Upstream Solenoid' ]) beamlinevars.append(['RESET:i:AmbDownStreamSol_Hum','%' ,'Humidity of Downstream Solenoid' ]) beamlinevars.append(['RESET:i:GasPanelBarPress1' , ' ' ,' ' ]) beamlinevars.append(['HD:coda:daq:availableRAID' , 'TB' ,'RAID disk space remaining' ]) # # EPICSvar_name units description beamhelivars = [] beamhelivars.append(['PWF1I04:spinCalc' , ' ' ,'Wien angle (Vertical)' ]) beamhelivars.append(['MFGANGLE' , ' ' ,'Wien angle (Solenoids)' ]) beamhelivars.append(['PWF1I06:spinCalc' , ' ' ,'Wien angle (Horizontal)' ]) beamhelivars.append(['IGL1I00DI24_24M' , ' ' ,'Insertable Half-wave plate' ]) beamhelivars.append(['psub_pl_pos' , ' ' ,'Rotating waveplate' ]) beamhelivars.append(['IGL1I00OD16_8' , ' ' ,'Pockels Cell ON/OFF' ]) beamhelivars.append(['SMRPOSA' , ' ' ,'Hall A Slit Position' ]) beamhelivars.append(['SMRPOSB' , ' ' ,'Hall B Slit Position' ]) beamhelivars.append(['SMRPOSC' , ' ' ,'Hall C Slit Position' ]) beamhelivars.append(['HELCLOCKd' , ' ' ,'Helicity Clock Read' ]) beamhelivars.append(['HELDELAYd' , ' ' ,'Helicity Delay Read' ]) beamhelivars.append(['HELTSETTLEd' , ' ' ,'Helicity Settle Read' ]) beamhelivars.append(['HELTSTABLEd' , ' ' ,'Helicity Stable Read' ]) beamhelivars.append(['HELPATTERNd' , ' ' ,'Helicity Pattern Read' ]) beamhelivars.append(['HELFREQ' , ' ' ,'Helicity Frequency' ]) # EPICSvar_name units description bcalvars = [] bcalvars.append(['BCUS:i::MainProgram-BCAL_US_1_Temp', 'C' ,' ' ]) bcalvars.append(['BCUS:i::MainProgram-BCAL_US_2_Temp', 'C' ,' ' ]) bcalvars.append(['BCUS:i::MainProgram-BCAL_US_3_Temp', 'C' ,' ' ]) bcalvars.append(['BCUS:i::MainProgram-BCAL_US_4_Temp', 'C' ,' ' ]) bcalvars.append(['BCDS:i::MainProgram-BCAL_DS_1_Temp', 'C' ,' ' ]) bcalvars.append(['BCDS:i::MainProgram-BCAL_DS_2_Temp', 'C' ,' ' ]) bcalvars.append(['BCDS:i::MainProgram-BCAL_DS_3_Temp', 'C' ,' ' ]) bcalvars.append(['BCDS:i::MainProgram-BCAL_DS_4_Temp', 'C' ,' ' ]) bcalvars.append(['BCUS:i::MainProgram-BCAL_US_1_Humidity', '%' ,' ' ]) bcalvars.append(['BCUS:i::MainProgram-BCAL_US_2_Humidity', '%' ,' ' ]) bcalvars.append(['BCUS:i::MainProgram-BCAL_US_3_Humidity', '%' ,' ' ]) bcalvars.append(['BCUS:i::MainProgram-BCAL_US_4_Humidity', '%' ,' ' ]) bcalvars.append(['BCDS:i::MainProgram-BCAL_DS_1_Humidity', '%' ,' ' ]) bcalvars.append(['BCDS:i::MainProgram-BCAL_DS_2_Humidity', '%' ,' ' ]) bcalvars.append(['BCDS:i::MainProgram-BCAL_DS_3_Humidity', '%' ,' ' ]) bcalvars.append(['BCDS:i::MainProgram-BCAL_DS_4_Humidity', '%' ,' ' ]) bcalvars.append(['BCAL_DS:CHILL:AIN_C', ' ' ,' ' ]) bcalvars.append(['BCAL_US:CHILL:AIN_C', ' ' ,' ' ]) # EPICSvar_name units description cdcvars = [] cdcvars.append(['GAS:i::FDC_Gas_Flow-MFC1_Flow', ' ' ,' ' ]) cdcvars.append(['GAS:i::FDC_Gas_Flow-MFC3_Flow', ' ' ,' ' ]) cdcvars.append(['GAS:i::FDC_Gas_Flow-MFC5_Flow', ' ' ,' ' ]) cdcvars.append(['GAS:i::FDC_CDC_Pressure-CDC_Pressure', ' ' ,' ' ]) cdcvars.append(['GAS:i::FDC_CDC_Pressure-CDC_Pressure_Inlet', ' ' ,' ' ]) cdcvars.append(['GAS:i::FDC_CDC_Pressure-CDC_Pressure_Outlet', ' ' ,' ' ]) cdcvars.append(['GAS:i::CDC_Temps-CDC_U1_Temp', 'C' ,' ' ]) cdcvars.append(['GAS:i::CDC_Temps-CDC_U2_Temp', 'C' ,' ' ]) cdcvars.append(['GAS:i::CDC_Temps-CDC_U3_Temp', 'C' ,' ' ]) cdcvars.append(['GAS:i::CDC_Temps-CDC_U4_Temp', 'C' ,' ' ]) cdcvars.append(['GAS:i::CDC_Temps-CDC_U5_Temp', 'C' ,' ' ]) cdcvars.append(['GAS:i::CDC_Temps-CDC_D1_Temp', 'C' ,' ' ]) cdcvars.append(['GAS:i::CDC_Temps-CDC_D2_Temp', 'C' ,' ' ]) cdcvars.append(['GAS:i::CDC_Temps-CDC_D3_Temp', 'C' ,' ' ]) cdcvars.append(['GAS:i::CDC_Temps-CDC_D4_Temp', 'C' ,' ' ]) cdcvars.append(['GAS:i::CDC_Temps-CDC_D5_Temp', 'C' ,' ' ]) cdcvars.append(['CDC:hv:A:1:v0set' , 'V' ,' ' ]) cdcvars.append(['CDC:hv:B:1:v0set' , 'V' ,' ' ]) cdcvars.append(['CDC:hv:A:1:vmon' , 'V' ,' ' ]) cdcvars.append(['CDC:hv:B:1:vmon' , 'V' ,' ' ]) # EPICSvar_name units description fdcvars = [] fdcvars.append(['FDC:CHILL:TEMP', 'C' ,' ' ]) fdcvars.append(['FDC:CHILL:FLOW', ' ' ,' ' ]) fdcvars.append(['FDC:CHILL:PRESS', ' ' ,' ' ]) fdcvars.append(['FDC:CHILL:ALARM1', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_Gas_Flow-MFC2_Flow', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_Gas_Flow-MFC4_Flow', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_Gas_Flow-MFC6_Flow', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_Gas_Flow-MFC7_Flow', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_Gas_Flow-MFC8_Flow', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_Gas_Flow-MFC9_Flow', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_CDC_Pressure-FDC_P1_Inlet_Press', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_CDC_Pressure-FDC_P2_Inlet_Press', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_CDC_Pressure-FDC_P3_Inlet_Press', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_CDC_Pressure-FDC_P4_Inlet_Press', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_CDC_Pressure-FDC_P1_Outlet_Press', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_CDC_Pressure-FDC_P2_Outlet_Press', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_CDC_Pressure-FDC_P3_Outlet_Press', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_CDC_Pressure-FDC_P4_Outlet_Press', ' ' ,' ' ]) fdcvars.append(['GAS:i::FDC_CDC_Pressure-PT506', ' ' ,' ' ]) html = '

\n' html += '

EPICS values

\n' html += MakeEPICS_TABLE('Beamline', beamlinevars, '#000') html += MakeEPICS_TABLE('Beam Helicity', beamhelivars, '#000') html += MakeEPICS_TABLE('BCAL', bcalvars, '#00F') html += MakeEPICS_TABLE('CDC', cdcvars, '#0F0') html += MakeEPICS_TABLE('FDC', fdcvars, '#F0F') html += '

\n' return html #====================================================== # Gather data html = '\n' html += MakeHEADER_HTML() html += '

\n' html += MakeEPICS_HTML() html += '

\n' html += MakeDAQ_HTML() html += '

\n' html += MakeDAQ_CONFIG_HTML() html += '\n\n' # Determine directory to hold tmp file DAQ_HOME = os.getenv('DAQ_HOME') if DAQ_HOME != None: tmp_dir = '%s/../work' % DAQ_HOME else: tmp_dir = '/tmp' # tmp filename fname = '%s/tmp_elog.html' % tmp_dir # Delete existing HTML file (if any) if os.path.exists(fname) : os.unlink(fname) # Write HTML to tmp file f = open(fname, 'w') f.write(html) f.close() # Title of log entry title = '"Run %s automated entry"' % RUN # write to e-Log cmd = ['/site/ace/certified/apps/bin/logentry' ] cmd.extend(['--title', title]) cmd.extend(['--html', '--body', fname]) cmd.extend(['--entrymaker','hdops']) cmd.extend(['--tag','Autolog']) for elog in ELOGS: cmd.extend(['--logbook', elog]) subprocess.call(cmd)