Installation and usage

Launching a beamline

ipython3
%run /path/to/your/beamline/script.py

or

ipython3 -i /path/to/your/beamline/script.py

Detector selection

Detectors have an active attribute which determines if they are included in data acquisition such as scans. The macro %lsdet indicates if each detector is active with an asterisk.

In [2]: lsdet

  name   class
-------------------------------------------------------------
* det2   <class 'contrast.detectors.Dummies.DummyDetector'>
* det3   <class 'contrast.detectors.Dummies.Dummy1dDetector'>
* det1   <class 'contrast.detectors.Dummies.DummyDetector'>

In [3]: ct
det2 : 0.5862324427414796
det3 : (100,)
det1 : 0.815299279368746

In [4]: det3.active=False

In [5]: lsdet

  name   class
-------------------------------------------------------------
* det2   <class 'contrast.detectors.Dummies.DummyDetector'>
  det3   <class 'contrast.detectors.Dummies.Dummy1dDetector'>
* det1   <class 'contrast.detectors.Dummies.DummyDetector'>

In [6]: ct
det2 : 0.26999817158517125
det1 : 0.4045182722290984

User levels

All Gadget instances have an associated user level. This means that certain motors can be hidden and protected while others are exposed through the macros. In this example, two sample motors are available to everyone while the undulator gap is higher level. This is not a security feature but meant to simplify the environment and reduce the risk of mistakes.

In [4]: %userlevel
Current userlevel: 1

In [5]: wa
motor     user pos.  limits            dial pos.  limits
---------------------------------------------------------------
samx      0.00       (0.00, 10.00)     0.00       (0.00, 10.00)
samy      0.00       (-5.00, 5.00)     0.00       (-5.00, 5.00)

In [6]: %userlevel 5

In [7]: wa
motor     user pos.  limits            dial pos.  limits
---------------------------------------------------------------
gap       0.00000    (None, None)      0.00       (None, None)
samx      0.00       (0.00, 10.00)     0.00       (0.00, 10.00)
samy      0.00       (-5.00, 5.00)     0.00       (-5.00, 5.00)

Defining custom macros

To write your own macro, simply write a class exposing an __init__ and a run method, and decorate it with @macro as above. The __init__ method gets the macro command-line arguments as positional arguments, while run should take no arguments. So, for example, the macro defined as:

In [12]: from contrast.environment import macro

In [13]: @macro
    ...: class My_Macro(object):
    ...:     """ My test macro """
    ...:     def __init__(self, arg1, arg2):
    ...:         self.arg1 = arg1
    ...:         self.arg2 = arg2
    ...:     def run(self):
    ...:         print(self.arg1, self.arg2)
    ...:

can be run like this.

In [14]: %my_macro 1 2
1 2

Place your macro in your favourite folder, and make sure to use absolute imports (from contrast...). Load the macro by running the file in your ipython interpreter.

%run /path/to/macro/file.py

Getting information out of macros

Although direct access to python objects allows you to probe the state of Gadgets,

In [7]: gap.user_position
Out[7]: 3.14

it is sometimes convenient to get results from macros. The run() method on macros can return usefult information. This can be done by manually constructing and running the macro object,

In [9]: from contrast.motors.Motor import Wm
In [10]: obj = Wm(gap)
In [11]: g = obj.run()
In [12]: g
Out[12]: 3.14

but in case you just want to execute a command without having to look up the python object at all, the output from the latest executed macro can always be found attached to the central env object.

In [13]: wm gap
motor     user pos.  limits           dial pos.  limits
-------------------------------------------------------------
gap       3.14000    (None, None)     3.14       (None, None)

In [14]: env.lastMacroResult
Out[14]: 3.14

If you’re not on the ipython console but in a script, this still works.

In [15]: from contrast.environment import runCommand
In [16]: runCommand('wm gap')
motor     user pos.  limits           dial pos.  limits
-------------------------------------------------------------
gap       3.14000    (None, None)     3.14       (None, None)

In [17]: env.lastMacroResult
Out[17]: 3.14

Direct access to python objects

If Gadget objects operate on underlying Tango devices, then Tango attributes are directly accessible on the objects themselves. PyTango provides tab completion and so these can be easily checked or corrected. Of course Gadget subclasses can provide nice getter and setter methods, but fixes are easily done.

In [7]: pilatus.det.energy
Out[7]: 10.0

In[8]: pilatus.lima.saving_mode
Out[8]: 'MANUAL'