This commit is contained in:
gac-x05la
2024-12-10 15:48:21 +01:00
committed by mohacsi_i
parent 169ae61100
commit b80ed2d71c
4 changed files with 121 additions and 114 deletions

View File

@@ -34,7 +34,7 @@ This is needed whenever you edit the scan or device files.
In order to start the BEC console interface, you first need to activate the corresponding venv.
This will also start the BEC GUI in a separate process and window:
```
source /data/test/x05la-test-bec/bec_deployment/bev_venv/bin/activate
source /data/test/x05la-test-bec/test/bec_venv/bin/activate
bec
```
@@ -43,16 +43,14 @@ bec
The BEC is deployed to a beamline specific network mounted folder that contains the main
repositories for the current installation, you can check it by:
```
[gac-x05la@x05la-bec-001 ~]$ ls -ltr /data/test/x05la-test-bec/bec_deployment/
total 4
drwxr-xr-x 7 gac-x05la unx-sls 4096 Aug 20 15:10 ophyd_devices
drwxr-xr-x 8 gac-x05la unx-sls 4096 Aug 20 15:10 bec_widgets
drwxr-xr-x 6 gac-x05la unx-sls 4096 Aug 20 15:11 bec_venv
-rw-r--r-- 1 gac-x05la unx-sls 326 Aug 20 15:15 bec_config.yaml
-rw-r--r-- 1 gac-x05la unx-sls 289 Aug 20 15:15 bec_client_config.yaml
drwxr-xr-x 15 gac-x05la unx-sls 4096 Aug 29 13:06 bec
drwxr-xr-x 7 gac-x05la unx-sls 4096 Sep 3 13:28 tomcat_bec
drwxr-xr-x 2 gac-x05la unx-sls 4096 Sep 6 11:22 logs
(bec_venv) [gac-x05la@x05la-bec-001 ~]$ ls -ltr /data/test/x05la-test-bec/test/
total 3
drwxr-xr-x 7 gac-x05la unx-nogroup 4096 Nov 19 15:25 ophyd_devices
drwxr-xr-x 8 gac-x05la unx-nogroup 4096 Nov 19 15:25 bec_widgets
drwxr-xr-x 6 gac-x05la unx-nogroup 4096 Nov 19 15:26 bec_venv
-rw-r--r-- 1 gac-x05la unx-nogroup 451 Nov 19 15:29 bec_config.yaml
drwxr-xr-x 6 gac-x05la unx-nogroup 4096 Nov 27 13:35 tomcat_bec
drwxr-xr-x 15 gac-x05la unx-nogroup 4096 Nov 27 14:03 bec
```
A short summary of the folder structure:
- bec_venv : The actual installation directory of the BEC framework
@@ -61,8 +59,9 @@ A short summary of the folder structure:
- ophyd_devices : Git repo as installation directory for shared ophyd devices
- tomcat_bec : Git repo as installation directory for Tomcat specific **scans, devices and configs.**
In short: You should use the bec_venv and only edit the tomcat_bec folder. And this is easily done
in Visual Studio Code, a really handy IDE if you have a fast connection:
In short: You should activate the installation in the bec_venv directory and only edit the
tomcat_bec folder. And this is easily done in Visual Studio Code, a really handy IDE if you
have a fast connection:
```
code &
```
@@ -111,24 +110,26 @@ If the previous two configuration attempts were unsuccesfull the bec_device_serv
without any devices. A single missing or mistyped IOC will cause a configuration failure, so once
you fixed you configs you can reload your YAML config file:
```
bec.config.update_session_with_file("/data/test/x05la-test-bec/bec_deployment/tomcat_bec/tomcat_bec/device_configs/microxas_test_bed.yaml")
bec.config.update_session_with_file("/data/test/x05la-test-bec/test/tomcat_bec/tomcat_bec/device_configs/microxas_test_bed.yaml")
```
If a single, unnecesary device doesn't come up , just comment it out.
## Early tests with GigaFrost and Aerotech
The main goal of the testbench is to test the various infrastructure component foreseen at the
The main goal of the testbench is to test the various infrastructure components foreseen at the
Tomcat beamlines and ensure their collaboration. Namely the rotation stage with the Aerotech smart
controller, the GigaFrost camera and the Standard-DAQ recording system. The individual repositories
have more documentation on the components, but as a short summary, the Aerotech Automation1 IOC is
a recently developed EPICS driver, the GigaFrost IOC is an ancient offshoot of Helge's camera driver
and the std-DAQ is a non-EPICS device that is controlled via a hybrid websocket and REST interface.
and the stdDAQ is a non-EPICS device that is controlled via a hybrid websocket and REST interface.
The DAQ also provides preview streams with hardcoded throttling.
Note that the standard bluesky event model applies, i.e. configure sets up the device, stage and
trigger for stepping interface and kickoff and collect for flyers. This will be updated with the
recently updated event model. Redundant staging raises an exception.
Note that while in the bluesky event model a manual configuration step sets up the device for a
scan. Followed by commands stage and trigger for stepping interface and kickoff and collect for
flyers. While in the BEC event model, stage is called on all enabled deviced on the deviceserver.
Calling stage also configures the device from the scaninfo. Moreover all steges are called in
parallel, regardless of device order. Redundant staging raises an exception.
### Seeing is believing (GUI)
@@ -141,116 +142,70 @@ caqtdm -macro "P=X02DA-ES1-SMP1" aeroauto1_ControllerOverview.ui
```
The std-DAQ doesn't have control panels, but the BEC can display the hard-coded preview streams.
The *daq_stream1* preview forwards displays 1 frames at a maximum of 5 Hz.
The *daq_stream0* preview forwards displays 1 frames at a maximum of 5 Hz.
So we just need to add the correct widgets to the GUI:
```
gui.add_dock('tomolive')
gui.panels['tomolive'].add_widget('BECFigure').image('daq_stream1')
```
### Short run with the GigaFrost and std-DAQ
This is a short, recorded test run with 2016x2016 frames at 100 Hz with the GigaFrost. The current
GigaFrost ophyd device includes the std-DAQ client, but they will probably be separated.
```
# Configure
d = {'ntotal': 1000000, 'nimages': 555, 'exposure': 5, 'period': 10}
dev.gfclient.configure(d)
# Stage GF, DAQ and preview
dev.gfclient.stage()
dev.daq_stream0.stage()
# Trigger a few sequences
def.gfclient.trigger()
def.gfclient.trigger()
# Unstage
def.gfclient.unstage()
dev.daq_stream0.unstage()
gui.panels['tomolive'].add_widget('BECFigure').image('daq_stream0')
```
## Reseting the Automation1 iSMC
## BEC scans at the testbench
The concept of scans is slightly different in bluesky and BEC. Bluesky strictly separates
the device logic in ophyd from the scan logic in plans. Devices are passed in as arguments
allowing finetuning their roles.
On the other hand, BEC has two scan interfaces and additional device specific scan logic is
placed on the ophyd device itself. The general idea is that the lower-level BEC scans should
be completely generic with absolutely minimal logic (although some examples counter this
argument). BEC devices live on the DeviceServer, and automatically participate in scans
whenever they are enabled. This puts the configuration role either on the ophyd device from
the scainfo or in the high level interface that anyways manages the enabling/disabling of devices.
The current repository has several implemented scans to test compliance with standard BEC
interfaces and partly cover the old EPICS IOC functionality.
- If a device is enabled for a scan it will be staged
- I.e. by the time stage finishes it must be configured
- This can be either manual or from the scan parameters
- Some scan parameters will overwrite the configuration (can be removed...)
- Certain scan kwargs will trigger the reconfiguration of a device
- The device will not try to make sure that the received configuration is correct
parameters
### anotherstepscan
Simple software step scan in the low-level API that almost calls the standard BEC scan routine. Its
only difference is that it overrides the burst to use Gigafrost's HW burst mode. The ophyd devices
are capable to allocate the required number of points for DAQ and position readback.
There's some electrical disturbance at SLS that can bring the system to a problematic state. A workaround is to remotely reset the iSMC:
```
dev.es1_ismc.reset()
```
FIXME: There is a known desync in PSO inputs upon iSMC restart that requires restarting the IOC.
## Scans at the testbench
The current repository has several implemented scans, often offering different solutions to the
same problem using different APIs while providing similar functionality. The BEC itself has two
scan APIs for low- and highlevel scans, and the fastest scans can be directly implemented on the
Automation1 iSMC. The implemented BEC scans combine motor motion, PSO triggering, Gigafrost and
stdDAQ control and position capture in internal or external triggering mode. They were
intentionally designed to provide the same interface, althogh not every combination was tested.
As I was unsure about the various triggering modes of the Gigafrost, so currently it's implemented
with only sofware trigger that is compatible with the standard bluesky step scanning interface.
### demostepscan
Simple step scan in the scripting API that performs the device configuration and hands over to
a standard BEC scan routine. Note that there's absolutely no readback from the GigaFrost so we
don't know when it finished acquiring.
```
def demostepscan(scan_start, scan_end, steps, exp_time=0.005, burst_at_each_point=1, settling_time=0, sync='event')
```
### gigastep
Simple step scan in the low level API that performs the device configuration loops over each
position in BEC and reads back the position data. Note that there's absolutely no readback from the GigaFrost so we
don't know when it finished acquiring.
```
scans.gigastep(scan_start, scan_end, steps, exp_time=0.005, settling_time=0.2, burst_at_each_point = 1, sync='event')
def demosanotherstepscantepscan(scan_start, scan_end, steps, exp_time=0.005, burst_at_each_point=1, settling_time=0, sync='event')
```
### snapnstep
Scripted step scan that sets up all components, creates an AeroScript file from template and
executes it on the Automation1 iSMC controller. Upon succesfull completion it reads back the
positions from the data capture.
NOTE: This scan just launches the GigaFrost, but hardware triggering is currently not implemented.
AeroScript controlled high-speed step-scan that sets up the devices and calls the corresponding
low-level scan API to substitute the jinja2 template file and launch the script. PSO and data
readback are configured and launched internally. It also waits for the script to finish.
```
scans.snapnstep(scan_start, scan_end, steps, exp_time=0.005, settling_time=0.2, burst_at_each_point = 1, sync='event')
anothersnapnstepscan(33, 180, 180, exp_time=0.005, exp_frames=1800, repeats=10)
```
### sequencescan
Scripted scan that sets up all components, creates an AeroScript file from template and executes it
on the Automation1 iSMC controller. Upon succesfull completion it reads back the positions from the
data capture. Position readback works wth both internal and external triggers.
NOTE: This scan just launches the GigaFrost, but hardware triggering is currently not implemented.
### anothersequencescan
AeroScript controlled fly scan that sets up the devices and calls the corresponding low-level scan
to substitute the jinja2 template file and launch the script. PSO and data readback are configured
and launched internally. It also waits for the script to finish. It might have problems with
configuring the readback of the number of repeats because that's done on the IOC,
```
scans.sequencescan(scan_start, gate_high, gate_low, repeats=1, repmode="PosNeg", exp_time=0.005, exp_frames=180, roix=2016, roiy=2016, sync="pso")
anothersequencescan(33, 180, 180, exp_time=0.005, exp_frames=1800, repeats=10)
```
### demosequencescan
Basic sequence scan in the high level API that calls the corresponding low-level scan with some
extra checks.
```
demosequencescan(scan_start, gate_high, gate_low, repeats=1, repmode="PosNeg", exp_time=0.005, exp_frames=180, roix=2016, roiy=2016, sync="pso")
```
### becsequencescan
Basic sequence scan script in BEC's high level interface. It a performs all trigger configurations
movements and readback from BEC.
```
becsequencescan(scan_start, gate_high, gate_low, repeats=1, repmode="PosNeg", exp_time=0.005, exp_frames=180, roix=2016, roiy=2016, sync="pso")
```

View File

@@ -27,11 +27,14 @@ class AcquireDark(Acquire):
"""
super().__init__(**kwargs)
self.burst_at_each_point = num
self.shutter = "hx" # change to the correct shutter device
self.scan_motors = ["eyex"] # change to the correct shutter device
#self.shutter = "eyex" # change to the correct shutter device
self.dark_shutter_pos = 0 ### change with a variable
def scan_core(self):
# close the shutter
yield from self.stubs.set_and_wait(device=[self.shutter], positions=[0])
yield from self._move_scan_motors_and_wait(self.dark_shutter_pos)
#yield from self.stubs.set_and_wait(device=[self.shutter], positions=[0])
yield from super().scan_core()

View File

@@ -94,7 +94,7 @@ def anothersequencescan(
Example:
--------
>>> demosequencescan(33, 180, 180, exp_time=0.005, exp_frames=1800, repeats=10)
>>> anothersequencescan(33, 180, 180, exp_time=0.005, exp_frames=1800, repeats=10)
"""
if not bl_check_beam():
raise RuntimeError("Beamline is not in ready state")
@@ -146,7 +146,7 @@ def anothersnapnstepscan(
Example:
--------
>>> demosequencescan(33, 180, 180, exp_time=0.005, exp_frames=1800, repeats=10)
>>> anothersnapnstepscan(33, 180, 180, exp_time=0.005, exp_frames=1800, repeats=10)
"""
if not bl_check_beam():
raise RuntimeError("Beamline is not in ready state")

View File

@@ -0,0 +1,49 @@
def fede_darks(num, exp_time=None, exp_period=None, roix=None, roiy=None):
""" Fede dark scan
This is a small BEC user-space scan that sets up the gigafrost and calls
the low-level dark collection scan.
Example:
--------
tutorialdarks(num=100, exp_time=5)
"""
###### TODO check how to pass only the required arguments
###### TODO what we want is a function common to PCO.edge and GF
# Configure gigafrost
cfg = {}
if exp_time != None:
cfg.update({"exposure_time_ms": exp_time})
if exp_period != None:
cfg.update({"exposure_period_ms": exp_period})
if roix != None:
cfg.update({"image_width": roix})
if roiy != None:
cfg.update({"image_height": roiy})
dev.gfcam.configure(d=cfg)
dev.gfcam.cfgAcqMode.set(1).wait()
dev.gfcam.cfgEnableExt.set(0).wait()
dev.gfcam.cfgEnableSoft.set(0).wait()
dev.gfcam.cfgEnableAlways.set(1).wait()
dev.gfcam.cfgTrigExt.set(0).wait()
dev.gfcam.cfgTrigSoft.set(0).wait()
dev.gfcam.cfgTrigTimer.set(0).wait()
dev.gfcam.cfgTrigAuto.set(1).wait()
dev.gfcam.cfgExpExt.set(0).wait()
dev.gfcam.cfgExpSoft.set(0).wait()
dev.gfcam.cfgExpTimer.set(1).wait()
dev.gfcam.cfgCntStartBit.set(0).wait()
# Commit changes to GF
dev.gfcam.cmdSetParam.set(1).wait()
print("Handing over to 'scans.acquire_dark")
scans.acquire_dark(num=num)