## Client usage ### Starting the command-line client The client can be started by running ```bash bec ``` ### Interface The client interface is based on the [IPython](https://ipython.org/) interactive shell. As seen in the screenshot below, the prompt is prefixed with, e.g. `demo [4/522] >>`. The prefix contains the name of the current session (demo), the current cell number (4) and the next scan number (522). ### Device access Devices are grouped in `dev`. This allows users to use tab-completion for finding devices. ```{image} ../assets/tab-complete-devices.png :align: center :alt: tab completion for finding devices :width: 300 ``` ```{hint} `dev` is imported as a builtin. As a result, you can access `dev` from everywhere. `dev` itself is just an alias for `bec.device_manager.devices`. ``` ### Inspect a device ```ipython LamNI [2/522] >> dev.samx Out[2]: Positioner(name=samx, enabled=True): -------------------- Details: Status: enabled Last recorded value: {'value': 0, 'timestamp': 1671796007.547235} Device class: SynAxisOPAAS Acquisition group: motor Acquisition readoutPriority: monitored Device tags: ['user motors'] User parameter: None -------------------- Config: delay: 1 labels: samx limits: [-50, 50] name: samx speed: 100 tolerance: 0.01 update_frequency: 400 ``` ### Move a motor There are two variants of device movements: `updated move` and `move`. #### Updated move (umv) A umv command blocks the command-line until the motor arrives at the target position (or an error occurs). ```python scans.umv(dev.samx, 5, relative=False) ``` #### Move (mv) A mv command is non-blocking, i.e. it does not wait until the motor reaches the target position. ```python scans.mv(dev.samx, 5, relative=False) ``` However, it can be made a blocking call by ```python scans.mv(dev.samx, 5, relative=False).wait() ``` The same mv command can also be executed by calling the device method `move` ```python dev.samx.move(5, relative=False) ``` ````{note} mv and umv can receive multiple devices, e.g. ```python scans.umv(dev.samx, 5, dev.samy, 10, relative=False) ``` ``````` ### Run a scan All currently available scans are accessible through `scans.`, e.g. ```python s = scans.line_scan(dev.samx, -5, 5, steps=10, exp_time=0.1, relative=False) ``` ### Inspect the scan data The return value of a scan is a python object of type `ScanReport`. All data is stored in `.scan.data`, e.g. ```python s = scans.line_scan(dev.samx, -5, 5, steps=10, exp_time=0.1, relative=False) print(s.scan.data) # print the scan data ``` ### Create a new script How to write a script ----------------------- Scripts are user defined functions that can be executed from the BEC console. They are stored in the ``scripts`` folder and can be edited with any text editor. The scripts are loaded automatically on startup of the BEC console but can also be reloaded by typing ``bec.load_all_user_scripts()`` in the BEC console. An example of a user script could be a function to move a specific motor to a predefined position: ```python def samx_in(): umv(dev.samx, 0) ``` or ```python def close_shutter(): print("Closing the shutter") umv(dev.shutter, 0) ``` A slightly more complex example could be a sequence of scans that are executed in a specific order: ```python def overnight_scan(): open_shutter() samx_in() for i in range(10): scans.line_scan(dev.samy, 0, 10, steps=100, exp_time=1, relative=False) samx_out() close_shutter() ``` This script can be executed by typing ``overnight_scan()`` in the BEC console and would execute the following sequence of commands: 1. Open the shutter 2. Move the sample in 3. Perform 10 line scans on the sample 4. Move the sample out 5. Close the shutter ### Create a custom scan As seen above, scans can be access through `scans.`. However, sometimes it is necessary to run a sequence of functions as if it were a scan. For example, we might want to run a grid scan (2D scan) with our sample motor stages but move the sample position in z after each 2D scan. Normally, this would create multiple output files that one would need to merge together later. This is where the scan definition comes in: it allows us to run a sequence of functions as if it were a scan, resulting in a single :term:`scan_number`, a single :term:`scanID` and a single output file. ```python @scans.scan_def def overnight_scan(): open_shutter() samx_in() for i in range(10): scans.grid_scan(dev.samy, 0, 10, steps=100, exp_time=1, relative=False) samx_out() close_shutter() ``` By adding the decorator ``@scans.scan_def`` to the function definition, we mark this function as a scan definition.