Differences between revisions 17 and 18
Revision 17 as of 2019-05-14 17:59:33
Size: 9974
Editor: MarkBarton
Comment:
Revision 18 as of 2019-05-15 20:46:07
Size: 11820
Editor: MarkBarton
Comment:
Deletions are marked like this. Additions are marked like this.
Line 31: Line 31:
Do `dir(vistools.Vis)` for a complete listing and `help(vistools.Vis.methodName)` for more details on individual methods. A typical signature is `dampGainWrite([self,] value, levels=[], chans=[], verbose=False, pair='none', withprefix='bare', matlab=False, dorw=2)`. The arguments are as follows:
 * `value`: a value or list of values to be written (write 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`, bring 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
Do `dir(vistools.Vis)` for a complete listing and `help(vistools.Vis.methodName)` for more details on individual methods.
Line 155: Line 147:
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.

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>> attachment:Gedit Setup.png

KAGRA/Subgroups/VIS/OpsManual/vistools (last edited 2019-05-15 20:46:07 by MarkBarton)