Differences between revisions 1 and 13 (spanning 12 versions)
Revision 1 as of 2019-04-24 10:22:39
Size: 759
Editor: MarkBarton
Comment:
Revision 13 as of 2019-05-13 17:30:18
Size: 8393
Editor: MarkBarton
Comment:
Deletions are marked like this. Additions are marked like this.
Line 5: Line 5:
== vistools.py usage modes ==
Line 7: Line 8:
 * [[#CLI|As a command line utility]].
Line 10: Line 10:
 * [[#CLI|As a command line utility]].
Line 12: Line 13:
<<Anchor(CLI)>>
== vistools.py as a command-line utility ==
<<Anchor(python)>>
=== vistools.py as a Python module ===
Line 15: Line 16:
<<Anchor(python)>>
== 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. 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'`, `'half full'`, `'half bare'` or `'bare'`; selects how much of the PV name to return (see next argument)
 * `pair`: can be `'pv'`, `'both'` or `'value'`; selects whether to return the channel name along with the read/written value
 * `matlab`: if `True`, returns lists with Matlab-style syntax
 * `dorw`: 0 -> no live channel access; 1 -> no live write channel access (read only); 2 -> live reading and writing
Not all methods are implemented for every block (feel free to add more based on existing patterns) but DAMP has a fairly complete set which illustrate the naming scheme:
 * `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.
Line 19: Line 60:
== vistools.py from within Guardian == === 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:
{{{
vis = None

def checkvis():
    global vis
    if vis == None:
        vis=vistools.Vis((SYSTEM,ezca))

class watchdog_check(GuardStateDecorator):
    """Decorator to check watchdog"""
    def pre_exec(self):
        global vis
        checkvis()
        if vis.trippedWds()!=[] or vis.trippedBioWds()!=[]:
            return 'TRIPPED'
# ...
class SAFE(GuardState):
    index = 30
    @watchdog_check
    def main(self):
        global vis
        notify('In SAFE')
}}}

<<Anchor(CLI)>>
=== 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).
{{{
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 standard level ordering - Python dictionaries don't preserve order
    '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
            },
            ...
         },
     },
     ....
}
}}}
== 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|{{attachment:Gedit Setup.png||width=300}}]]

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. 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', 'half full', 'half bare' or 'bare'; selects how much of the PV name to return (see next argument)

  • pair: can be 'pv', 'both' or 'value'; selects whether to return the channel name along with the read/written value

  • matlab: if True, returns lists with Matlab-style syntax

  • dorw: 0 -> no live channel access; 1 -> no live write channel access (read only); 2 -> live reading and writing

Not all methods are implemented for every block (feel free to add more based on existing patterns) but DAMP has a fairly complete set which illustrate the naming scheme:

  • 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.

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:

vis = None

def checkvis():
    global vis
    if vis == None:
        vis=vistools.Vis((SYSTEM,ezca))

class watchdog_check(GuardStateDecorator):
    """Decorator to check watchdog"""
    def pre_exec(self):
        global vis
        checkvis()
        if vis.trippedWds()!=[] or vis.trippedBioWds()!=[]:
            return 'TRIPPED'
# ...
class SAFE(GuardState):
    index = 30
    @watchdog_check
    def main(self):
        global vis
        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).

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 standard level ordering - Python dictionaries don't preserve order
    '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
            }, 
            ...
         },
     },
     ....
}

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)