KAGRA VIS Operations Manual - vistools.py
vistools.py is a Python module and command-line utility for manipulating the suspensions. It lives in /opt/rtcds/userapps/release/vis/k1/scripts (although it may get moved to /opt/rtcds/userapps/release/vis/common/scripts and there is a symlink to it in /opt/rtcds/userapps/release/vis/k1/guardian. Nearby there may be a test version vistoolstest.py.
vistools.py usage modes
vistools.py has three modes of use:
vistools.py as a Python module
vistools.py is primarily an ordinary Python module which provides the class Vis. Each instance of Vis represents a single suspension and can be created with any of the following forms:
BS = vistools.Vis('BS') # an Ezca instance with prefix 'K1:' is created internally BS = vistools.Vis('VIS-BS') # channel name prefix style BS = vistools.Vis('VIS_BS') # Guardian file name style BS = vistools.Vis(('BS',ezca)) # ezca should be an existing ezca.Ezca instance with prefix 'K1:'; 'BS' can be 'VIS-BS' or 'VIS_BS'
A Vis object has a large number of methods which are mostly organized and named by blocks of filters of the same function (e.g., DAMP) at different levels of the suspension:
BS.masterSwitchWrite('ON') # turns the master switch on BS.dampGainWrite(1.0) # sets all gain values in all DAMP blocks to 1.0. BS.dampGainWrite(1.0,levels=['IP']) # sets all gain values in the IP DAMP block to 1.0. BS.dampGainWrite(1.0,levels=['IP'],chans=['L','T']) # sets the gain values for the L and T channels of the IP DAMP block to 1.0
Do dir(vistools.Vis) for a complete listing and help(vistools.Vis.methodName) for more details on individual methods. Not all methods are implemented for every block (feel free to add more based on existing patterns) but DAMP has a complete set which illustrate the naming scheme for filter block commands:
dampPvs: Return a list of PVs for DAMP blocks.
dampInputSwitchWrite: Write 'ON' or 'OFF' to the INPUT switch in DAMP blocks.
dampInputSwitchRead: Read the INPUT switch in DAMP blocks.
dampOutputSwitchWrite: Write 'ON' or 'OFF' to the OUTPUT switch in DAMP blocks.
dampOutputSwitchRead: Read the OUTPUT switch in DAMP blocks.
dampOffsetSwitchWrite: Write 'ON' or 'OFF' to the OFFSET switch in DAMP blocks.
dampHoldSwitchWrite: Write 'ON' or 'OFF' to the HOLD switch in DAMP blocks.
dampOffsetWrite: Write a value or list of values to the OFFSET field in DAMP blocks.
dampGainRead: Read the gain value in DAMP blocks.
dampGainWrite: Write a value or list of values to the GAIN field in DAMP blocks.
dampFilterModuleEnableWrite: Write 'ON' or 'OFF' to the filter switches in DAMP blocks.
dampRampWrite: Write a value or list of values to the RAMP field in DAMP blocks.
dampGainRampingRead: Read the gain ramping state (GRAMP) in DAMP blocks.
dampOffsetRampingRead: Read the offset ramping state (ORAMP) in DAMP blocks.
dampRampingRead: Read the overall ramping state (GRAMP or ORAMP) in DAMP blocks.
dampPressButton: Simulate a press of the CLEAR HISTORY ('CLEAR') or LOAD COEFFICIENTS ('LOAD') button in DAMP blocks.
Similarly, OSEM2EUL has a complete set for matrix blocks:
o2ePvs: Return PV names for all or selected matrix elements.
o2eDefs: Return default values for all or selected matrix elements.
o2eRead: Read all or selected matrix elements.
o2eWriteValue: Write a common value into all or selected matrix elements.
o2eWriteArray: Write an array into all or selected matrix elements
lmWriteDefaults: Write default values for all or selected matrix elements
vistools.py from within Guardian
The usage from within Guardian is a bit complicated. According to some versions of the Guardian documentation, there is supposed to be a global Ezca instance called ezca which can be used for channel access. And according to some versions of the documentation, it is supposed to have prefix K1:VIS_BS_ or the like (which gets prepended to channel name fragments passed to it). If you run the Guardian in interactive mode, e.g.,
guardian -i VIS_BS
then there is indeed a global ezca object, but it has prefix just K1:, so the appropriate setup is
vis=vistools.Vis((SYSTEM,ezca))
However the environment seen by an actual Guardian script is different again: the Ezca object is not global but only available within the GuardState classes that define states. Worse, creating a second one at global scope causes channel access errors. Therefore, the initialization of vistools.py has to be done inside a state definition. The solution used by the Type B Guardian extends the decorator watchdog_check to also check whether the Vis object has been initialized and do it if necessary:
visObj = None def checkvis(): global visObj if visObj == None: visObj = vistools.Vis((SYSTEM,ezca)) class watchdog_check(GuardStateDecorator): """Decorator to check watchdog""" def pre_exec(self): global visObj checkvis() if visObj.trippedWds()!=[] or visObj.trippedBioWds()!=[]: return 'TRIPPED' # ... class SAFE(GuardState): index = 30 @watchdog_check def main(self): global visObj notify('In SAFE')
vistools.py as a command-line utility
vistools.py Internal Organization
vistools.py uses two large nested dictionary structures, visTypes and visData to define what groups of channels are available. A typical entry in visTypes specifies a particular suspension (e.g., BS) in terms of a generic type (e.g., 'TYPEB') plus watchdog and BIO information:
visTypes = { ..., ('K1','BS') : {'type': 'TYPEB', 'watchdogs': typebwd, 'bio' : typebbio}, ... }
where
typebwd = {'IOP':'DACKILL','IP':'IP_WDMON', 'F0':'F0_WDMON','F1':'F1_WDMON','BF':'BF_WDMON', 'IM':'IM_WDMON','TM':'TM_WDMON'} typebbio = {'GAS':'BIO_GAS_MON','IP':'BIO_IP_MON','GAS':'BIO_GAS_MON','IMV':'BIO_IMV_MON','TM':'BIO_TM_MON'}
Then, a typical entry in visData specifies a generic suspension type, which is further structured by level ('IP', 'F0', 'F1' etc) and optionally by sensor actuator group ('osemConfig', 'olConfig' etc). (The concept of a sensor-actuator group was more important historically when vistools.py was less smart about ignoring missing keys and every level had to have the same set of keys, even though many of them had value None - all the OSEM-related blocks could be declared as non-existent with a single entry 'osemConfig':None.)
visData = { 'master' : 'MASTERSWITCH', # a switch not associated with any particular level 'commissioning' : 'COMMISH_STATUS', # another global switch 'levelorder': ['IP','F0','F1','BF','SF','IM','TM'], # define a default level ordering 'levels' : { # define the various levels in the suspension ... 'IM':{ # define the intermediate mass level 'dofs' : ['L', 'T', 'V', 'R', 'P', 'Y'], # a list of related channels 'isichans' : ['X', 'Y', 'RZ', 'Z', 'RX', 'RY'], # another list of related channels ... 'cart2eul' : { # a cdsMuxMatrix block 'blockname':'CART2EUL', # the Simulink block name, used for constructing channel names 'inames':'isichans', # input channels; reference to the list defined above 'onames':'dofs', # output channels; reference to the list defined above 'default':[...] # default values for matrix elements }, 'osemConfig' : { # a sensor-actuator group 'chans' : ['V1', 'V2', 'V3', 'H1', 'H2', 'H3'], # a list of input channels 'dofs' : ['L', 'T', 'V', 'R', 'P', 'Y'], # a list of output channels 'inf' : {'blockname':'OSEMINF', 'names':'chans'}, # a block with a group of cdsFilt units 'eul2osem' : { # a cdsMuxMatrix block 'blockname':'EUL2OSEM','inames':'dofs', 'onames':'chans', 'default':[[...],[...]],...]) # each sublist represents an _output_! }, ... }, ... }, }, .... }
Most of the read/write commands are based on one of the following building block methods, which provide a standard set of utilities:
switch([self,] pv, setting, enable, verbose=False, pair='value', withprefix='bare', matlab=False, dorw=2)
write([self,] pv, value, verbose=False, pair='none', withprefix='bare', matlab=False, dorw=2)
writelist([self,] pvs, values, verbose=False, pair='none', withprefix='bare', matlab=False, dorw=2)
read([self,] pv, verbose=False, pair='value', withprefix='bare', matlab=False, dorw=2)
readlist([self,] pvs, verbose=False, pair='value', withprefix='bare', matlab=False, dorw=2)
The typical arguments are as follows:
pv or pvs: a process variable (PV) or list of PVs to be read/written to/from.
value/values: a numeric value or list of values to be written (write methods only)
setting: a switch value ('ON' or 'OFF') to be written (switch methods only)
levels: a list of levels to restrict the request or change the default order, e.g, ['IP','F0','F1','BF']
chans: a list of channels within a block to restrict the request or change the default order, e.g., ['L','T'] for IP DAMP.
verbose: if True, print debugging information, typically the channel names written to
withprefix: can be 'full', 'halffull', 'halfbare' or 'bare'; selects how much of the PV name to return (see next argument)
pair: can be 'pv', 'both', 'value' or 'none'; selects whether to return the channel name along with the read/written value
matlab: if True, returns lists with Matlab-style syntax (1/0 instead of True/False; {} instead of [] for lists)
dorw: 0 -> no live channel access; 1 -> no live write channel access (read only); 2 -> live reading and writing
Then there is a higher level group of methods that work with all or selected PVs of a particular type:
genNumWrite(self, pvfn, suffix, value, levels=[], chans=[], verbose=False, pair='none', withprefix='bare', matlab=False, dorw=2)
genNumRead(self, pvfn, suffix, levels=[], chans=[], verbose=False, pair='value', withprefix='bare', matlab=False, dorw=2)
genSwitchRead(self, pvfn, bits, levels=[], chans=[], verbose=False, pair='value', withprefix='bare', matlab=False, dorw=2)
genFilterModuleEnableRead(self, pvfn, filters=[], levels=[], chans=[], verbose=False, pair='none', withprefix='bare', matlab=False, dorw=2)
genFilterModuleEnableWrite(self, pvfn, enable, filters=[], levels=[], chans=[], verbose=False, pair='none', withprefix='bare', matlab=False, dorw=2)
genSwitchWrite(self, pvfn, suffix, enable, levels=[], chans=[], verbose=False, pair='none', withprefix='bare', matlab = False, dorw=2)
All of these take an argument pvfn which is a custom method for a particular block with signature pvfn([self,] levels=levels,chans=chans) or the like and returns a list of appropriate PVs for that block.
vistools.py Style Guide
vistools.py should have groups of 4 spaces for indentation. To select this in gedit, select Automatic Indentation off, Tab Width 4, Use Spaces on in the Tab Width menu in the lower window frame:<<br>>