Skip to content

Commit 8b8a38b

Browse files
author
Kay Kasemir (ky9)
committed
beamline settings...
1 parent b864e0a commit 8b8a38b

File tree

5 files changed

+78
-73
lines changed

5 files changed

+78
-73
lines changed

doc/getting_started.rst

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,16 @@ Unfortunately, the "correct" way to set a PV is not discernible from the outside
268268
It requires knowledge about the implementation of a PV in the IOC.
269269
And even if the correct way to set a PV is known, having to type
270270
all parameters for each `Set` command can be cumbersone.
271-
The PyScanClient library offers :ref:`scan_settings` where the ideal
272-
parameters for each PV can be configured once, and wrappers for the
273-
basic `Set` and `Wait` commands will then automatically use them as a default.
271+
The PyScanClient :ref:`scan_settings` provide a way to configure default parameters
272+
for each PV.
273+
Wrappers for the basic `Set`, `Loop` and `Wait` commands then use these defaults.
274+
For an example, see `example/beamline_setup.py`:
275+
276+
.. literalinclude:: ../example/beamline_setup.py
277+
278+
The code in `example/beamline1.py`, `example/beamline2.py` and
279+
`example/beamline3.py` shows how to take advantage of the
280+
scan settings.
274281

275282

276283
Table Scan

example/beamline1.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
from beamline_setup import *
22

3-
# N-Dim scan
4-
cmds = ndim(('xpos', 1, 10), Delay(0.2))
5-
print cmds
6-
id = scan_client.submit(cmds)
7-
print scan_client.waitUntilDone(id)
3+
# N-Dim scan with motors
4+
# At each point, wait for pcharge which rises at about 1e9 per second
5+
# Then log how many neutrons we got
6+
cmds = ndim(('motor_x', 1, 3), ('motor_y', 1, 3),
7+
TakeData('pcharge', 3*1e9),
8+
'neutrons')
9+
10+
# Note how the defaults apply a readback to motors,
11+
# how TakeData is expanded into basic commands etc.
12+
print(cmds)
813

9-
# Simulated pcharge rises at about 1e9 per second
10-
cmds = ndim(('xpos', 1, 3), ('ypos', 1, 3), TakeData('pcharge', 3*1e9), 'neutrons')
11-
print cmds
14+
# The scan_client is already configured with the correct IP address
1215
id = scan_client.submit(cmds)
13-
print scan_client.scanInfo(id)
14-
# scan_client.waitUntilDone(id)
16+
print(scan_client.scanInfo(id))
17+
print(scan_client.waitUntilDone(id))
18+

example/beamline2.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22

33
# Table
44
cmds = table_scan(
5-
[ 'xpos', 'ypos', 'Wait For', 'Value'],
5+
[ 'motor_x', 'motor_y', 'Wait For', 'Value'],
66
[
7-
[ 1, [ 2, 4, 6], 'pcharge', 3*1e9 ],
8-
[ 3, 8, 'pcharge', 3*1e9 ],
7+
[ 1, [ 2, 4, 6], 'pcharge', 3*1e9 ],
8+
[ 3, 8, 'pcharge', 3*1e9 ],
99
])
10-
print cmds
10+
print(CommandSequence(cmds))
1111
id = scan_client.submit(cmds)
1212
scan_client.waitUntilDone(id)
1313

1414
# Dump motor positions
1515
data = scan_client.getData(id)
16-
table = createTable(data, 'xpos', 'ypos')
16+
table = createTable(data, 'motor_x', 'motor_y')
1717
for (x, y) in zip(*table):
18-
print "%d, %d" % (x, y)
18+
print("%d, %d" % (x, y))

example/beamline3.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
cmds.append(SetChopper(1.7, 45.0))
99
cmds.append(TakeData('pcharge', 5e9))
1010
cmds.append(Set('setpoint', 1))
11-
print cmds
11+
print(cmds)
1212

1313
result = scan_client.simulate(cmds)
14-
print result['simulation']
14+
print(result['simulation'])
1515

1616
id = scan_client.submit(cmds)
17-
print "Submitted scan #%d" % id
17+
print("Submitted scan #%d" % id)
1818

1919

example/beamline_setup.py

Lines changed: 45 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,49 @@
11
"""Example for beamline specific setup
22
3-
Uses the scan server example database
4-
plus some local PVs to fake devices.
3+
All scripts that access the scan server
4+
should start with
5+
6+
'from beamline_setup import *'
57
"""
68

9+
# Get all scan commands
710
from scan import *
811

9-
# Note that the basic Loop/Set/Wait commands are replaced by
10-
# those that utilize custom scan settings
12+
# Replace basic Loop/Set/Wait commands with wrappers
13+
# that utilize custom scan settings
1114
from scan.util import SettingsBasedLoop as Loop
1215
from scan.util import SettingsBasedSet as Set
1316
from scan.util import SettingsBasedWait as Wait
1417

15-
# Custom scan settings
18+
# Each "beamline" or more generally setup that uses
19+
# the PyScanClient should create its own ScanSettings
1620
class BeamlineScanSettings(ScanSettings):
1721
def __init__(self):
1822
super(BeamlineScanSettings, self).__init__()
19-
# Define several PVs to use completion etc.
20-
self.defineDeviceClass("shutter", readback=True)
21-
self.defineDeviceClass("chopper:.*", completion=True)
22-
self.defineDeviceClass(".*daq.*", completion=True)
23+
24+
# Define settings based on PV name patterns
25+
# (regular expressions).
26+
# Order matters! List most generic patterns first,
27+
# specific PV names last.
28+
# For example, motors should use completion, and check a readback
2329
self.defineDeviceClass("motor_.", completion=True, readback=True)
24-
self.defineDeviceClass("setpoint", completion=True, readback="readback", tolerance=0.1)
30+
# The specific motors in the simulation.db, however, don't support completion
31+
self.defineDeviceClass("motor_x", completion=False, readback=True)
32+
self.defineDeviceClass("motor_y", completion=False, readback=True)
33+
self.defineDeviceClass("shutter", readback=True)
34+
# The simulated "setpoint" uses a different PV "readback" as its readback.
35+
# (readback=False skips readback check
36+
# readback=True calls getReadbackName(pv) which typically returns the PV itself,
37+
# readback='whatever' uses provided PV
38+
# )
39+
self.defineDeviceClass("setpoint", completion=False, readback="readback", tolerance=0.1, timeout=20)
40+
# When waiting for proton charge or neutron counts, use "increase by"
2541
self.defineDeviceClass("pcharge", comparison="increase by")
2642
self.defineDeviceClass("neutrons", comparison="increase by")
2743

28-
# Used by UI to suggest devices on which one can 'wait'
44+
# Each site may add more to its site-specific configuration.
45+
# The example/opi for alignment uses these to
46+
# populate drop-downs
2947
self.settable = [ "motor_x", "motor_y" ]
3048
self.waitable = [ "seconds", "pcharge" ]
3149
self.loggable = [ "signal" ]
@@ -38,11 +56,10 @@ def getReadbackName(self, device_name):
3856
if "motor" in device_name:
3957
return device_name + ".RBV"
4058

41-
scan_settings = BeamlineScanSettings()
4259
# Install beam line specific scan settings
60+
scan_settings = BeamlineScanSettings()
4361
setScanSettings(scan_settings)
4462

45-
4663
# 'Meta Commands'
4764
def Start():
4865
"""Start data acquisition"""
@@ -58,13 +75,12 @@ def TakeData(counter, limit):
5875
return Sequence(Start(), Wait(counter, limit), Stop())
5976

6077
def SetChopper(wavelength, phase):
61-
return Sequence(scan_settings.Set('loc://chopper:run(0)', 0),
62-
scan_settings.Set('loc://chopper:wlen(0)', wavelength),
63-
scan_settings.Set('loc://chopper:phs(0)', phase),
64-
scan_settings.Set('loc://chopper:run(0)', 1)
78+
return Sequence(Set('loc://chopper:run(0)', 0),
79+
Set('loc://chopper:wlen(0)', wavelength),
80+
Set('loc://chopper:phs(0)', phase),
81+
Set('loc://chopper:run(0)', 1)
6582
)
6683

67-
6884
def table_scan(headers, rows):
6985
"""Create table scan with pre/post/start/stop for this beam line"""
7086
table = TableScan(headers, rows,
@@ -78,37 +94,15 @@ def table_scan(headers, rows):
7894
# Create a scan client, using the host name that executes the scan server
7995
scan_client = ScanClient('localhost')
8096

81-
82-
83-
84-
85-
import unittest
86-
87-
class TestScanClient(unittest.TestCase):
88-
def testSet(self):
89-
self.assertEqual(str(Set('setpoint', 1)), "Set('setpoint', 1, completion=True, readback='readback')")
90-
self.assertEqual(str(Set('setpoint', 1, completion=False)), "Set('setpoint', 1, readback='readback')")
91-
self.assertEqual(str(Set('setpoint', 1, readback=False)), "Set('setpoint', 1, completion=True)")
92-
self.assertEqual(str(Set('setpoint', 1, timeout=10)), "Set('setpoint', 1, completion=True, readback='readback', timeout=10)")
93-
94-
def testLoop(self):
95-
self.assertEqual(str(Loop('x', 1, 5, 0.5)), "Loop('x', 1, 5, 0.5)")
96-
self.assertEqual(str(Loop('motor_x', 1, 5, 0.5)), "Loop('motor_x', 1, 5, 0.5, completion=True, readback='motor_x')")
97-
self.assertEqual(str(Loop('motor_x', 1, 5, 0.5, completion=False)), "Loop('motor_x', 1, 5, 0.5, readback='motor_x')")
98-
self.assertEqual(str(Loop('motor_x', 1, 5, 0.5, completion=False, readback=False)), "Loop('motor_x', 1, 5, 0.5)")
99-
self.assertEqual(str(Loop('motor_x', 1, 5, 0.5, Comment(''), completion=False, readback=False)),
100-
"Loop('motor_x', 1, 5, 0.5, [ Comment('') ])")
101-
self.assertEqual(str(Loop('motor_x', 1, 5, 0.5, Comment('a'), Comment('b'), completion=False, readback=False)),
102-
"Loop('motor_x', 1, 5, 0.5, [ Comment('a'), Comment('b') ])")
103-
self.assertEqual(str(Loop('motor_x', 1, 5, 0.5, [ Comment('a'), Comment('b') ], completion=False, readback=False)),
104-
"Loop('motor_x', 1, 5, 0.5, [ Comment('a'), Comment('b') ])")
105-
106-
def testWait(self):
107-
self.assertEqual(str(Wait('whatever', 1)), "Wait('whatever', 1, comparison='>=')")
108-
self.assertEqual(str(Wait('pcharge', 1)), "Wait('pcharge', 1, comparison='increase by')")
109-
self.assertEqual(str(Wait('pcharge', 1, timeout=5)), "Wait('pcharge', 1, comparison='increase by', timeout=5)")
110-
self.assertEqual(str(Wait('pcharge', 1, timeout=5, comparison='>=')), "Wait('pcharge', 1, comparison='>=', timeout=5)")
111-
112-
97+
# As a convenience, `python beamline_setup.py` prints settings
11398
if __name__ == '__main__':
114-
unittest.main()
99+
from scan.util.scan_settings import getScanSettings
100+
101+
print("Beam Line scan settings")
102+
print("=======================")
103+
for setting in getScanSettings().device_settings:
104+
print(setting)
105+
print("")
106+
print("Scan Client")
107+
print("===========")
108+
print(scan_client)

0 commit comments

Comments
 (0)