-
Notifications
You must be signed in to change notification settings - Fork 1
Scripting
Scripting in IBEX is done using genie_python. The genie_python reference manual gives a full account of what functions are available in genie_python. This page is intended to give a broad guide to scripting for the beginner and novice user.
- Running genie_python commands
- Common genie_python commands
- Converting Open Genie to genie_python
- Creating and running instrument scripts
- Creating and running user scripts
- Tips from the developers
There is also some specific `scripting advice for the Muon Front END<#MuonFEScriptGuidance>`__.
When running genie_python from an interactive console such as from
the GUI or after running C:\Instrument\Apps\Python\genie_python.bat,
the genie module will be aliased to g. Genie commands can then
be accessed by using the prefix g.[COMMAND_NAME]. For example:
g.start()
g.cset("BLOCK_1",1)
g.abort()
This is particularly useful from the GUI which will auto-complete commands and provide tool tips describing each function and its arguments.
Note that in many cases, arguments will be optional. For instance,
begin can be used as g.begin() despite supporting all of the
arguments period, meas_id, meas_type, meas_subid,
sample_id, delayed, quiet, paused, and verbose.
Many genie_python commands share the same name with their Open Genie
equivalent so it will often be very straightforward to find the function
you're looking for. Still, here is a list of the most commonly used
genie_python commands. This is not a complete list. For full
information, consult the genie_python reference manual.
| Command | Description | Example |
|---|---|---|
| begin | Starts a new run | g.begin() |
| end | Ends the current run | g.end() |
| abort | Aborts the current run | g.abort() |
| pause | Pauses the current run | g.pause() |
| resume | Resumes the current run after it has been paused | g.resume() |
| Command | Description | Example |
|---|---|---|
| cget | Gets the useful values associated with a block | g.cget("NEW_BLOCK") |
| cset | Sets the setpoint and runcontrol settings for blocks | g.cset("NEW_BLOCK",1) |
| get_pv | Gets the value for the specified PV | g.get_pv("IN:INSTNAME:IOC_01:STAT") |
| set_pv | Sets the value for the specified PV | g.set_pv("IN:INSTNAME:IOC_01:STAT",1) |
| Command | Description | Example |
|---|---|---|
| get_uamps | Gets the current number of micro-amp hours | g.get_uamps() |
| get_frames | Gets the current number of good frames | g.get_frames() |
| get_runstate | Gets the current status of the instrument as a string | g.get_runstate() |
| get_mevents | Gets the total counts for all the detectors | g.get_mevents() |
| get_totalcounts | Gets the total counts for the current run | g.get_totalcounts() |
| waitfor | Interrupts execution until certain conditions are met | g.waitfor("NEW_BLOCK",value=1) |
| waitfor_block | Interrupts execution until block reaches specific value | g.waitfor_block("NEW_BLOCK",1) |
| waitfor_time | Interrupts execution for a specified amount of time | g.waitfor_time(1) |
| waitfor_frames | Interrupts execution to wait for number of total good frames to reach parameter value | g.waitfor_frames(1000) |
| waitfor_uamps | Interrupts execution to wait for a specific total charge | g.waitfor_uamps(9.9) |
| waitfor_runstate | Waits for a particular instrument run state | g.waitfor_runstate("paused") |
| waitfor_move | Waits for all motion or specific motion to complete | g.waitfor_move("NEW_BLOCK") |
If you know a little bit of Python already, converting Open Genie
scripts to genie_python is very often straightforward. Even if
you're new to Python, once you know a few simple pieces of syntax,
you'll be able to convert many scripts without issue.
We've included some - Common ``genie_python` commands <#common-genie_python-commands>`__ on this page, but for a full list refer to the genie_python reference manual.
One thing where there is no direct comparison is with indentation.
In Python, different code blocks are identified by their indentation
level. In many programming languages, code blocks are encased in curly
braces ({...}), but Python uses indentation. For example:
print "No indent"
def my_func():
print "1 indent. Inside the function"
if True:
print "2 indents. Inside the if clause"
print "2 indents. Still inside the if clause"
print "1 indent. In the function but not the if clause"
print "No indent. Outside the function"
Typically an indent is 3 or 4 spaces. Tabs can be used too, but
Python won't recognise that a tab is the same as 4 spaces so can lead to
problems. It's often best to avoid them. This might be a new concept if
you've only ever written Open Genie, but trust us in that it opens up a
lot of ways to make scripts more powerful, easier to read and more
reliable.
| Open Genie syntax |
genie_python syntax |
Comments |
|---|---|---|
| PROCEDURE my_func | def my_func(): | This is the standard way to define a function in Python |
| begin | g.begin() | Many functions in genie_python have the same name as in Open Genie. In these cases, prepend g. to idicate the method belongs to genie_python and append () to tell Python to execute the method with no arguments |
| my_func_2 100 | my_func_2(100) | To execute a function, give its name and then the argument in brackets. This is a user-defined function, not a genie_python function, so it has no g. in front. |
| my_func_3 100 200 | my_func_2(100,200) | As above, except that multiple arguments are separated by a comma |
| waitfor seconds=20 | g.waitfor(seconds=20) | Some methods can take named arguments. In these cases you simply give named arguments in the form [name]=[value]. Note that you can mix named and unnamed arguments, but unnamed arguments always appear at the start of the argument list. This section gives a more detailed description |
| cset/nocontrol MY_BLOCK=value | g.cset('MY_BLOCK',value,runcontrol=False) | Some Open Genie commands take optional arguments. The same principle applies as in the above example. |
| # This is a comment | # This is a comment | Comments are the same in both languages |
Different instruments may have specific scripts that are required for
multiple users. To make accessing these easier, genie_python loads
instrument scripts at startup.
For the most part, this is the same as creating-user-scripts.
Unlike user scripts, instrument scripts should be placed in
C:\Instrument\Settings\config\[MACHINE_NAME]\Python. Once the script
has been created, edit the file inst.py in the same directory and
add the line from [MY_FILE] import * where [MY_FILE] is the name
of your file without the .py file extension. This will include the
new script in the list of scripts loaded at startup. Best to avoid file
names containing spaces, it can be
done
but it's easier to just not do it.
Everything in the instrument scripts will be executed when
genie_python is started. This includes - Making functions available
to be called later - Setting variables - Running methods Typically, most
code in instrument scripts will be contained within functions
(procedures in Open Genie language), but it's important to be aware that
anything that isn't will be included too. For example, if an instrument
script is loaded:
a = 1
def print_a():
print str(a)
then the user can call print_a, but they can also use the variable
a, and change its value, which may not be desirable. If instead the
script was:
def print_a():
a = 1
print str(a)
then the user could only access print_a() and the value could not be
changed.
Please note: When you are running scripts, the script is being executed on the instrument control PC. This means that the script itself has to be stored on the instrument control PC. It also means that any path names in your scripts refer to locations on the instrument control PC (unless you are referring to network drives).
Once the script is loaded, anything from the script will be available
using the inst package reference. For instance if your script
contains the function my_function you can call:
inst.my_function()
Whilst using the scripting perspective in the Ibex GUI, users will also
benefit from the same auto-complete feature as they do with
genie_python commands.
- First, we need to create a script file. By default, user scripts
should be placed in
C:\scripts. Navigate to your desired directory and create the script file with extension.py. - Write some
genie_python! - Save the file
We have glossed over step 2 because Python is a very powerful scripting language. Combined with Open Genie, the potential scope of a script is enormous, and well beyond the scope of this guide. For example though, here is a simple script that executes a calibration run.
# Change the title calibration_run_title = "Calibration run 1, 29th September" g.change(title=calibration_run_title) # Begin the run print "Beginning calibration run : " + calibration_run_title g.begin() # Wait for 100 uamps g.waitfor(uamps=100) # End the run g.end() print "Calibration run finished successfully"
Please note: When you are running scripts, the script is being executed on the instrument control PC. This means that the script itself has to be stored on the instrument control PC. It also means that any path names in your scripts refer to locations on the instrument control PC (unless you are referring to network drives).
Once you've created your script, it's time to run it. There are a number of ways of launching a Python script.
- Launch the Ibex GUI
- Navigate to the scripting perspective
- Run the command
g.load_script("C:\path\to\script\my_script.py")where the path and script name are updated appropriately- Note that if you omit the absolute path to the file (i.e.
C:\path\to\script) thengenie_pythonwill look in the current script directory. By default this isC:\scriptsbut can be viewed and set with the commandsg.get_script_dir()andg.set_script_dir()respectively.
- Note that if you omit the absolute path to the file (i.e.
- When the script is loaded, any procedures in the script will be run automatically. If the script contains any function, you will now be able to call them from within the scripting window.
- Launch a
genie_pythonterminal fromC:\Instrument\Apps\Python\by runninggenie_python.bat - Follow the above starting at step 3.
As this is Python, genie_python conforms to the standard pattern of
calling Python functions. The arguments to the function are contained
within brackets and the variables passed in as a comma-separated list.
Ordering is important but can be overridden by using named variables,
for instance the following are all correct and equivalent:
g.change_beamline_pars("PAR1",1)
g.change_beamline_pars(name="PAR1",value=1)
g.change_beamline_pars(value=1,name="PAR1")
g.change_beamline_pars("PAR1",value=1)
In the last example, named and unnamed variables are mixed. Unnamed variables must precede named variables. The following examples are not valid
g.change_beamline_pars(name="PAR1",1) # Named variable before unnamed g.change_beamline_pars(1,"PAR1") # Cannot change order of unnamed variables
Using named variables can be very useful in avoiding mistakes. For instance, getting the order of high and low limits the wrong way round. For instance this example:
g.change_monitor(1,10,0)
is wrong and wouldn't work. Instead, we could have written:
g.change_monitor(1,high=10,low=0)
which would have worked and makes it clear for whoever comes to edit the code in future.