Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

EPICS PV step scans use the BlueSky software from BNL (https://nsls-ii.github.io/bluesky/).  In this mode one or more PV's are modified while the DAQ is paused, then data is acquired (, either for a :

  1.  a fixed number of shots,
  2.  a fixed time, or
  3.  until the event code sequencer completes.

Then or a fixed time) then the DAQ is paused again and the PV is modified again for the next "step".  BlueSky supports complex coordinated motion of multiple PV's.

An example python script has been created to demonstrate support for PV scans with the RIX instrument.

...

The parameters of the scan should be updated to match the requirements of the experiment.  To do so, update this section of rix_bluesky_rixscan.py:

Code Block
languagetext
titlerix_bluesky_rixscan.py scan parameters
# Scan motor1 from -10 to 10, stopping
# at 15 equally-spaced points along the way and reading dets.
RE(scan(dets, motor1, -10, 10, 15))

...

Code Block
languagetext
titlerix_bluesky_rixscan.py demo
$ python rix_bluesky_rixscan.py 

Transient Scan ID: 1     Time: 2020-12-10 18:24:53
Persistent Unique Scan ID: '2092a9ca-160c-4b52-8683-256f699e1e01'
New stream: 'primary'
+-----------+------------+------------+
|   seq_num |       time |     motor1 |
+-----------+------------+------------+
|         1 | 18:24:58.5 |    -10.000 |
|         2 | 18:24:59.6 |     -8.571 |
|         3 | 18:25:00.6 |     -7.143 |
|         4 | 18:25:01.6 |     -5.714 |
|         5 | 18:25:02.7 |     -4.286 |
|         6 | 18:25:03.7 |     -2.857 |
|         7 | 18:25:04.8 |     -1.429 |
|         8 | 18:25:05.8 |      0.000 |
|         9 | 18:25:06.8 |      1.429 |
|        10 | 18:25:07.9 |      2.857 |
|        11 | 18:25:08.9 |      4.286 |
|        12 | 18:25:10.0 |      5.714 |
|        13 | 18:25:11.0 |      7.143 |
|        14 | 18:25:12.0 |      8.571 |
|        15 | 18:25:13.1 |     10.000 |
+-----------+------------+------------+
generator scan ['2092a9ca'] (scan num: 1)
Code Block
languagetext
titlelab3_bluesky_lab3scan.py demo
$ python lab3_bluesky_lab3scan.py 

Transient Scan ID: 1     Time: 2021-02-21 16:33:15
Persistent Unique Scan ID: 'fb4d16b7-2844-431e-bb77-cc90cd1f2fe0'
New stream: 'primary'
+-----------+------------+------------+
|   seq_num |       time |     motor1 |
+-----------+------------+------------+
|         1 | 16:33:19.7 |    -10.000 |
|         2 | 16:33:19.8 |     -8.571 |
|         3 | 16:33:19.9 |     -7.143 |
|         4 | 16:33:20.0 |     -5.714 |
|         5 | 16:33:20.1 |     -4.286 |
|         6 | 16:33:20.3 |     -2.857 |
|         7 | 16:33:20.4 |     -1.429 |
|         8 | 16:33:20.5 |      0.000 |
|         9 | 16:33:20.6 |      1.429 |
|        10 | 16:33:20.7 |      2.857 |
|        11 | 16:33:20.8 |      4.286 |
|        12 | 16:33:20.9 |      5.714 |
|        13 | 16:33:21.0 |      7.143 |
|        14 | 16:33:21.1 |      8.571 |
|        15 | 16:33:21.2 |     10.000 |
+-----------+------------+------------+
generator list_scan ['fb4d16b7'] (scan num: 1)

...

  1. Make sure all the detectors to be used are configured properly.
  2. Make sure the timing system is configured properly.  As of this writing, RIX uses readout groups 2 and 5.
  3. When you're ready to record a scan, don't forget to enable recording before running rix_bluesky_rixscan.py (or use the --record argument)!  In the control GUI, the disk icon has a diagonal line over it when not recording.
  4. Use the "normal" DAQ interface to select the detectors of interest as "active" and assign their readout groups.
  5. Put the DAQ in ALLOCATED or CONNECTED state. Now, you are ready to run rix_bluesky_rixscan.py.

The rix_bluesky_rixscan.py script accepts several command line arguments. If you are relying on the default settings, make sure they are correct for your experiment now, not just way back in 2020 when the script was first written.

...

Code Block
languagetext
titlerix_bluesky_rixscan.py help
$ python bluesky_rix.py -h
usage: rix_bluesky_rixscan.py [-h] [-B PVBASE] [-p {0,1,2,3,4,5,6,7}] [-x XPM]
                      [-C COLLECT_HOST] [-t TIMEOUT] [-c READOUT_COUNT]
                      [-g GROUP_MASK] [--config ALIAS[-g GROUP_MASK] [--config ALIAS]
                           [--detname DETNAME] [--scantype SCANTYPE] [--seqctl SEQCTL [SEQCTL ...]] [--record] [-v]

optional arguments:
   -h, --help help           show this help message and exit
  -Bshow PVBASEthis  help  message  and       PV base (default DAQ:NEH)
  exit
  -p {0,1,2,3,4,5,6,7}   platform (default 2)
   -xC XPM COLLECT_HOST              collection masterhost XPM (default 0drp-neh-ctl001)
   -Ct COLLECT_HOSTTIMEOUT       collection host (default drp-neh-ctl001)
  -t TIMEOUT            timeout msec (default 10000)
   -c READOUT_COUNT COUNT        # of events to aquire at each step (default 120)
   -g GROUP_MASK             bit mask of readout groups (default 36)
   --config ALIAS ALIAS           configuration alias (default BEAM)
   --detname  DETNAME          detector  name     be verbose

Detector Configuration Scans

These scans use the same "step" idea described above for EPICS PV step-scans, but instead alter a detector configuration object on each step.  Currently this has been done for the EPIX area detector to take data in the various gain ranges.

Script Control of Run Stop/Start

One can control the DAQ (e.g. to stop and start runs on a timer) with scripts like this:

Code Block
languagebash
#!/bin/bash(default 'scan')
  --scantype SCANTYPE   scan type (default 'scan')
  --seqctl SEQCTL [SEQCTL ...]
                        sequence control (e.g. DAQ:NEH:XPM:0:SeqReset 4 [DAQ:NEH:XPM:0:SeqDone])
  --record              enable recording of data
  -v                                    
while [ 1 ]
do
echo going to configured
daqstate -p 0 -P tmo -C drp-neh-ctl001 --state configured
sleep 5
echo going to running
daqstate -p 0 -P tmo -C drp-neh-ctl001 --state running
sleep 600
done

Running Scans with Hutch Python

An example hutch-python scan session in RIX:

be verbose

The optional "seqctl" argument is sent to the DAQ on the configure transition.  The optional "detname" argument is used by the DAQ to determine which readout group to use to count events.

  • The first argument to "seqctl" is the PV to restart the sequence
  • The second argument is a bit mask of sequence engines to restart
  • The third (optional) argument is which variable to use to detect that the sequence is complete.  It defaults to "StepDone" in the daq code (control.py) when using "number of counts" to end the step.  One uses "SeqDone" when using an XPM sequence, and the third case is when we're using the accelerator to burst, and this is set to listen to a variable from them telling them that the burst is complete.

step_value Handling

PV scans automatically generate a 1-based step counter named "step_value" and record it alongside motor positions, like so:

Code Block
languagetext
titlestep_value demo
$ xtcreader -f /cds/data/psdm/rix/rixx43518/xtc/rixx43518-r0518-s007-c000.xtc2 -d
  ...
event 3,   BeginStep transition: time 1003603961.730737554, env 0x06040024, payloadSize 147 extent 159
Found 4 names
0: 'step_value' rank 0, type 7
'step_value': 1
1: 'step_docstring' rank 1, type 10
'step_docstring': "{"detname": "scan", "scantype": "scan", "step": 1}"
2: 'fast_motor1' rank 0, type 9
'fast_motor1': 1.000000
3: 'fast_motor2' rank 0, type 9
'fast_motor2': 1.000000
  ...
event 8,   BeginStep transition: time 1003603961.964178292, env 0x060e0024, payloadSize 147 extent 159
Found 4 names
0: 'step_value' rank 0, type 7
'step_value': 2
1: 'step_docstring' rank 1, type 10
'step_docstring': "{"detname": "scan", "scantype": "scan", "step": 2}"
2: 'fast_motor1' rank 0, type 9
'fast_motor1': 3.250000
3: 'fast_motor2' rank 0, type 9
'fast_motor2': 3.250000
  ...

One can override "step_value" by creating a motor named "step_value" and including it among other motors in the scan. This step count also appears in the JSON formatted "step_docstring" automatically.

Group Mask Parameter

We believe the group mask parameter to daq.configure() is passed to control.py and then given to the enable transition.  This programs the xpm's StepGroups PV so the xpm knows which readout group to disable when the sequence completes.  We can't disable all readout groups because another partition may use different readout groups on the same xpm.  It's possible control.py already knows this information, so conceivable we could eliminate this parameter and so reduce complexity, but we're not sure at the time of this writing. - weaver/cpo Feb. 8, 2024.

Detector Configuration Scans

These scans use the same "step" idea described above for EPICS PV step-scans, but instead alter a detector configuration object on each step.  Currently this has been done for the EPIX area detector to take data in the various gain ranges. Python code for this can be found here: https://github.com/slac-lcls/lcls2/blob/master/psdaq/psdaq/app/epixhr_pedestal_scan.py

BebDetector Timing Scan

  • works with any BebDetector
  • there is a control script "generic_timing_scan" in the daq environment in psdaq/psdaq/cas/generic_timing_scan.py.  assumes name "start_ns".  does not use bluesky.  could be changed to any valid config variable in a BebDetector's configuration object, but the "dictionary" variable name must be written correctly in generic_timing_scan.py (e.g. for start_ns it is [f'{args.detname}:user.start_ns']).
  • each step completes when this xpm variable DAQ:NEH:XPM:2:PART:0:StepDone goes to one.  This variable DAQ:NEH:XPM:2:PART:0:StepGroups says which readout groups to enable/disable.
  • start_ns has a minimum value determined by the L0Delay setting for the readout group.
    • L0Delay is in units of 14/13us has a range of 0-100 (there's an off-by-one somewhere).  We get notification of beam ~95us early (ideally 100us, but the beam is faster than the timing packet) so for fast detectors we want to set L0Delay to about 95:  having a larger number reduces the need for DAQ buffering (front end, kcu card, but NOT cpu buffering since we can't guarantee that DMA happens promptly)
  • generic_timing_scan -p 0 -C drp-srcf-mon001 --detname tmo_fzppiranha_0 --events 71000 --linear 108000 112000 1000 --record 0 -v
    • note that the start of the timing scan must respect the L0Delay setting for the readout group
  • We analyzed in ami with a graph like this.  If steps were too short and the detector rates too high it was possible for ami to miss all the data for a step:

Image Added

Script Control of Run Stop/Start

One can control the DAQ (e.g. to stop and start runs on a timer) with scripts like this:

Code Block
languagebash
#!/bin/bash                                                                                      
while [ 1 ]
do
echo going to configured
daqstate -p 0 -P tmo -C drp-neh-ctl001 --state configured
sleep 5
echo going to running
daqstate -p 0 -P tmo -C drp-neh-ctl001 --state running
sleep 600
done

Running Scans with Hutch Python

UED hutch python logs are here:  /cds/group/pcds/pyps/apps/hutch-python/ued/logs/2022_04
GUI version logs: /cds/data/iocData/ioc-ued-bsgui-qs/iocInfo

An example hutch-python scan session in RIX.  "rix3" also takes a "--debug" option to increase verbosity.  TMO has a similar "tmo3" command.

Code Block
languagetext
rix-daq:~> rix3
Loading local disk python env pcds-4.1.4
      _      _____       _   _                 
     (_)    |  __ \     | | | |                
 _ __ ___  _| |__) |   _| |_| |__   ___  _ __  
| '__| \ \/ /  ___/ | | | __| '_ \ / _ \| '_ \ 
| |  | |>  <| |   | |_| | |_| | | | (_) | | | |
|_|  |_
Code Block
rix-daq:~> rix3
Loading local disk python env pcds-4.1.4
      _      _____       _   _                 
     (_)    |  __ \     | | | |                
 _ __ ___  _| |__) |   _| |_| |__   ___  _ __  
| '__| \ \/ /  ___/ | | | __| '_ \ / _ \| '_ \ 
| |  | |>  <| |   | |_| | |_| | | | (_) | | | |
|_|  |_/_/\_\_|    \__, |\__|_| |_|\___/|_| |_|
                    __/ |                      
                   |___/                       

INFO     Selected default hutch-python daq platform: 0
INFO     Loading debug tools...

(lines removed for brevity)

In [1]: daq = get_daq() # in tmo this requires a "bluesky=True" kwarg

In [2]: dets = [daq]daq platform: 0
INFO     Loading debug tools...

(lines removed for brevity)

In [31]: daq.configure(motors=[sim.fast_motor1, sim.fast_motor2],events=10,record=True)
INFO     configure - configure: 2 motors
Out[31]: ({}, {})

In [42]: RE(bp.scan(dets[daq], sim.fast_motor1, 1, 10, sim.fast_motor2, 1, 10, 5))


Transient Scan ID: 1     Time: 2021-0710-0720 1712:0006:3021
Persistent Unique Scan ID: 'e1a966bd81544aea-c12d5fb7-429d4017-95edb03d-ea73f7dd7211a1ea8d15c174'
New stream: 'primary'
+-----------+------------+-------------+-------------+
|   seq_num |       time | fast_motor1 | fast_motor2 |
+-----------+------------+-------------+-------------+
|         1 | 1712:0006:4633.3 |           1 |           1 |
|         2 | 1712:0006:5934.14 |        3.25 |        3.25 |
|         3 | 1712:0106:0835.35 |         5.5 |         5.5 |
|         4 | 1712:0106:1836.36 |        7.75 |        7.75 |
|         5 | 1712:0106:2837.37 |          10 |          10 |
+-----------+------------+-------------+-------------+
generator scan ['e1a966bd81544aea'] (scan num: 1)



Out[4]: ('e1a966bd-c12d-429d-95ed-ea73f7dd7211',)

In Out[52]: daq.push_socket.send_string('shutdown'('81544aea-5fb7-4017-b03d-a1ea8d15c174',)

In [63]: daq.comm_thread.join()

In [7]: quit
rix-daq:~> 

If the "shutdown" and "join" commands are not issued then the "quit" command will hang, and you will have to control-C to end the program.

Arguments to get_daq() in rix (these are set by modifying daq.args.<attribute>, e.g. daq.args.c):

...

quit
rix-daq:control>  

In UED, Zach also recommended this way of doing a scan with a fake motor inside hutch python:

Code Block
RE(motor_pv_scan('TEST:MOT', 1, 10, 10, events=360, record=False))

These are the parameters that are settable in daq.configure (see these with "daq.configure?" in hutch-python):

Code Block
Signature:
daq.configure(
    *,
    motors=None,
    group_mask=None,
    events=None,
    record=None,
    detname=None,
    scantype=None,
    serial_number=None,
    alg_name=None,
    alg_version=None,
)
Docstring:
Set parameters for scan.

Keyword arguments:
motors -- list of motors, optional
    Motors with positions to include in the data stream
group_mask -- int, optional
    Bit mask of readout groups
events -- int, optional
    Number of events per scan point
record -- bool, optional
    Enable recording of data
detname -- str, optional
    Detector name
scantype -- str, optional
    Scan type
serial_number -- str, optional
    Serial number
alg_name -- str, optional
    Algorithm name
alg_version -- list of 3 version numbers, optional
    Algorithm version
File:      /u1/rixopr/conda_envs/pcds-5.0.0/lib/python3.9/site-packages/psdaq/control/BlueskyScan.py
Type:      method

Other hutch-python parameters are settable in this per-hutch configuration file:

Code Block
rix-daq:control> more /cds/group/pcds/pyps/apps/hutch-python/rix/conf.yml 
hutch: rix

# Locate happi database
db: /reg/g/pcds/pyps/apps/hutch-python/device_config/db.json

# Hutch-specific imports
load: rix.beamline

# DAQ interface configuration
daq_type: lcls2

daq_host: drp-neh-ctl001

daq_platform:
  default: 2
rix-daq:control> 

LCLS2 DAQ Python interface FAQ

Q1) How to find the current DAQ state?

A1) Call control.getStatus()

Q2) How to determine whether the DAQ has already been configured?

A2) Check if the current DAQ state is any of "configured", "starting", "paused", or "running".

Q3) How to force a "configure" transition before the next scan?

A3) Set the DAQ state to "connected".