This commit is contained in:
487
script/cpy/local.py
Normal file
487
script/cpy/local.py
Normal file
@@ -0,0 +1,487 @@
|
||||
###################################################################################################
|
||||
# Deployment specific global definitions - executed after startup.py
|
||||
###################################################################################################
|
||||
|
||||
###################################################################################################
|
||||
#Devices for PShell standard scans
|
||||
###################################################################################################
|
||||
|
||||
import random
|
||||
|
||||
####################################################################################################
|
||||
# Simulated devices
|
||||
####################################################################################################
|
||||
|
||||
add_device(DummyMotor("m1"), True)
|
||||
add_device(DummyMotor("m2"), True)
|
||||
add_device(DummyRegister("reg1",3), True)
|
||||
add_device(DummyPositioner("p1"),True)
|
||||
add_device(MotorGroupBase("mg1", m1, m2), True)
|
||||
add_device(MotorGroupDiscretePositioner("dp1", mg1), True)
|
||||
|
||||
|
||||
#Initial Configuration
|
||||
if p1.getConfig().unit is None:
|
||||
p1.getConfig().minValue = 0.0 #Not persisted
|
||||
p1.getConfig().maxValue = 1000.0
|
||||
p1.getConfig().unit = "mm"
|
||||
p1.getConfig().save()
|
||||
p1.initialize()
|
||||
|
||||
if dp1.getConfig().positions is None:
|
||||
dp1.getConfig().positions = ["Park","Ready","Out","Clear"]
|
||||
dp1.getConfig().motor1 = ["0.0","4.0","8.0" ,"0.0"]
|
||||
dp1.getConfig().motor2 = ["0.0","5.0","3.0" ,"NaN"]
|
||||
dp1.getConfig().save()
|
||||
dp1.initialize()
|
||||
|
||||
|
||||
|
||||
#Update
|
||||
m1.setMonitored(True)
|
||||
m2.setMonitored(True)
|
||||
|
||||
####################################################################################################
|
||||
# Readable / Writable objects can be created and used in scans
|
||||
####################################################################################################
|
||||
|
||||
class MyWritable(Writable):
|
||||
def write(self, value):
|
||||
#print ("Write: ",value)
|
||||
pass
|
||||
|
||||
class MyReadable(Readable):
|
||||
def read(self):
|
||||
return random.random()
|
||||
|
||||
class MyReadableArray(ReadableArray):
|
||||
def read(self):
|
||||
ret = []
|
||||
for i in range (self.getSize()):
|
||||
ret.append(random.random())
|
||||
return to_array(ret,'d')
|
||||
|
||||
def getSize(self):
|
||||
return 20
|
||||
|
||||
class MyReadableArrayNumpy(ReadableArray):
|
||||
def read(self):
|
||||
ret = numpy.ones(self.getSize(),'d')
|
||||
return ret
|
||||
|
||||
def getSize(self):
|
||||
return 20
|
||||
|
||||
class MyReadableMatrix(ReadableMatrix):
|
||||
def read(self):
|
||||
ret = []
|
||||
for i in range (self.getHeight()):
|
||||
ret.append([random.random()] * self.getWidth())
|
||||
return to_array(ret, 'd')
|
||||
|
||||
def getWidth(self):
|
||||
return 80
|
||||
|
||||
def getHeight(self):
|
||||
return 40
|
||||
|
||||
class MyReadableMatrixNumpy(ReadableMatrix):
|
||||
def read(self):
|
||||
ret = numpy.ones((self.getHeight(), self.getWidth()),'d')
|
||||
for i in range(self.getHeight()):
|
||||
ret[i]=i
|
||||
return to_array(ret, 'd')
|
||||
|
||||
def getWidth(self):
|
||||
return 80
|
||||
|
||||
def getHeight(self):
|
||||
return 40
|
||||
|
||||
|
||||
ao1 = MyWritable("ao1")
|
||||
ao2 = MyWritable("ao2")
|
||||
ai1 = MyReadable("ai1")
|
||||
ai2 = MyReadable("ai2")
|
||||
wf1 = MyReadableArray("wf1")
|
||||
wf2 = MyReadableArrayNumpy("wf2")
|
||||
im1 = MyReadableMatrix("im1")
|
||||
im2 = MyReadableMatrixNumpy("im2")
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Imaging
|
||||
####################################################################################################
|
||||
|
||||
configured = os.path.exists(GenericDevice.getConfigFileName("src1"))
|
||||
|
||||
add_device(RegisterMatrixSource("src1", im1.proxy), True)
|
||||
add_device(RegisterMatrixSource("src2", im2.proxy), True)
|
||||
|
||||
#src1.setPolling(100)
|
||||
#src2.setPolling(100)
|
||||
|
||||
#Some configuration for so the imaging will work out of the box
|
||||
if not configured:
|
||||
src1.getConfig().colormapAutomatic = True
|
||||
src1.getConfig().colormap = Colormap.Temperature
|
||||
src1.getConfig().save()
|
||||
src2.getConfig().colormapAutomatic = True
|
||||
src2.getConfig().save()
|
||||
|
||||
|
||||
|
||||
|
||||
###################################################################################################
|
||||
#Embedding Bluesky
|
||||
###################################################################################################
|
||||
|
||||
|
||||
import signal
|
||||
signal.signal = lambda *args: None
|
||||
from bluesky import RunEngine
|
||||
from bluesky.callbacks import CallbackBase
|
||||
from bluesky.callbacks.best_effort import BestEffortCallback
|
||||
from bluesky.utils import install_kicker, DuringTask
|
||||
#from bluesky.utils import ProgressBarManager
|
||||
from ophyd.sim import det1, det2, det3, det4, det, motor, motor1, motor2, motor3,img, sig, direct_img, pseudo1x3
|
||||
from ophyd import Signal
|
||||
from ophyd.signal import EpicsSignal
|
||||
from bluesky.plans import count, scan, rel_scan, list_scan, grid_scan, list_grid_scan
|
||||
from bluesky.simulators import summarize_plan
|
||||
import bluesky.plan_stubs as bps
|
||||
from bluesky.plan_stubs import mv
|
||||
import bluesky.preprocessors as bpp
|
||||
from bluesky.preprocessors import SupplementalData
|
||||
#import databroker
|
||||
from databroker import Broker
|
||||
#import suitcase
|
||||
#import suitcase.csv
|
||||
|
||||
CAN_PAUSE=True
|
||||
|
||||
|
||||
|
||||
#def on_ctrl_cmd(cmd):
|
||||
def on_abort(parent_thread):
|
||||
global RE
|
||||
# print ("Control command: ", cmd)
|
||||
# if cmd=="abort":
|
||||
if "RE" in globals():
|
||||
if RE.state not in ['idle','paused', 'pausing']:
|
||||
if CAN_PAUSE:
|
||||
print ("Abort command: Run Engine aborted")
|
||||
sys.stderr=None
|
||||
RE.abort("User abort")
|
||||
return
|
||||
else:
|
||||
print ("Abort command: Run Engine pause request")
|
||||
RE.request_pause()
|
||||
return
|
||||
tid=parent_thread.ident
|
||||
exception = KeyboardInterrupt
|
||||
ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), ctypes.py_object(exception))
|
||||
|
||||
def on_close(parent_thread):
|
||||
on_abort(parent_thread)
|
||||
|
||||
|
||||
|
||||
|
||||
from collections import deque
|
||||
|
||||
is_scan_paused = False
|
||||
class MyHandler(CallbackBase):
|
||||
|
||||
def __init__(self):
|
||||
self.queue= deque(maxlen=1000)
|
||||
|
||||
def clear(self):
|
||||
self.queue.append(("clear",None))
|
||||
|
||||
def start(self, doc):
|
||||
self.queue.append(("start",doc))
|
||||
|
||||
def stop(self, doc):
|
||||
self.queue.append(("stop",doc))
|
||||
|
||||
def descriptor(self, doc):
|
||||
self.queue.append(("descriptor",doc))
|
||||
|
||||
def resource(self, doc):
|
||||
self.queue.append(("resource",doc))
|
||||
|
||||
def event(self, doc):
|
||||
self.queue.append(("event",doc))
|
||||
while is_scan_paused:
|
||||
time.sleep(0.1)
|
||||
|
||||
def datum(self, doc):
|
||||
self.queue.append(("datum",doc))
|
||||
|
||||
def event_page(self, doc):
|
||||
self.queue.append(("event_page",doc))
|
||||
|
||||
def datum_page(self, doc):
|
||||
self.queue.append(("datum_page",doc))
|
||||
|
||||
handler= MyHandler()
|
||||
re_scan=re_res=None
|
||||
|
||||
|
||||
class EventProcessingTask(DuringTask):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def block(self, blocking_event):
|
||||
global start_doc,descriptor_coc, stop_doc, event_doc, re_scan, re_res, __return__,__exception__
|
||||
re_scan=None
|
||||
while True:
|
||||
done = blocking_event.wait(.1)
|
||||
if done:
|
||||
return
|
||||
try:
|
||||
check_pause()
|
||||
while len(handler.queue):
|
||||
(msg, doc) = handler.queue.popleft()
|
||||
#print("-> " ,msg)
|
||||
if msg=="start":
|
||||
global start_doc
|
||||
start_doc=doc
|
||||
writables=doc.get('motors',[])
|
||||
|
||||
readables=doc.get('detectors',[])
|
||||
start,stop, steps=-1,-1,doc.get('num_intervals',-1)
|
||||
try:
|
||||
if doc.get("plan_name","")=="grid_scan":
|
||||
steps=[x-1 for x in doc['shape']]
|
||||
start=[x[0] for x in doc['extents']]
|
||||
stop=[x[1] for x in doc['extents']]
|
||||
elif doc.get("plan_name","")=="list_grid_scan":
|
||||
steps=[-1 for x in doc['shape']]
|
||||
start=[x[0] for x in doc['extents']]
|
||||
stop=[x[1] for x in doc['extents']]
|
||||
elif doc.get("plan_name","")=="scan":
|
||||
_,start,stop = doc['plan_args']['args']
|
||||
elif doc.get("plan_name","")=="list_scan":
|
||||
_,positions=doc['plan_args']['args']
|
||||
start = min(positions)
|
||||
stop = max(positions)
|
||||
except:
|
||||
pass
|
||||
|
||||
diags=None
|
||||
monitors=None
|
||||
meta={}
|
||||
for k in start_doc.keys():
|
||||
o=start_doc[k]
|
||||
if o is not None:
|
||||
if k=="extents":
|
||||
o = str(o)
|
||||
elif type(o) in (list, tuple):
|
||||
o=to_array(o,'s')
|
||||
elif type(o) == dict:
|
||||
o=str(o)
|
||||
meta[k]=o
|
||||
re_res = None
|
||||
re_scan = ManualScan(writables, readables ,start, stop, steps, diags=diags, monitors=monitors, meta=meta)
|
||||
re_scan.scan.setCanPause(CAN_PAUSE)
|
||||
re_scan.start()
|
||||
|
||||
elif msg=="stop":
|
||||
global stop_doc
|
||||
stop_doc=doc
|
||||
if re_scan is not None:
|
||||
if not re_scan.scan.isCompleted():
|
||||
re_scan.end()
|
||||
re_res = re_scan.scan.getResult()
|
||||
sys.stderr=jep_stderr
|
||||
elif msg=="descriptor":
|
||||
global descriptor_doc
|
||||
descriptor_doc=doc
|
||||
elif msg=="event":
|
||||
global event_doc
|
||||
event_doc=doc
|
||||
if (re_scan is not None) and not (re_scan.scan.isCompleted()):
|
||||
setpoints=[]
|
||||
readbacks=[]
|
||||
detectors=[]
|
||||
data=doc['data']
|
||||
for dev in start_doc.get("motors",[]):
|
||||
readbacks.append(data[dev])
|
||||
try:
|
||||
setpoints.append(data[dev+"_setpoint"])
|
||||
except:
|
||||
setpoints.append(data[dev])
|
||||
for dev in start_doc.get("detectors",[]):
|
||||
v=data[dev]
|
||||
if str(type(v))=="<class 'jep.PyJArray'>":
|
||||
v=numpy.array(v)
|
||||
detectors.append(v)
|
||||
re_scan.append (setpoints, readbacks, detectors)
|
||||
elif msg=="resource":
|
||||
pass
|
||||
elif msg=="datum":
|
||||
pass
|
||||
elif msg=="event_page":
|
||||
pass
|
||||
elif msg=="datum_page":
|
||||
pass
|
||||
elif msg=="clear":
|
||||
pass
|
||||
elif msg=="check_pause":
|
||||
pass
|
||||
elif msg=="read":
|
||||
try:
|
||||
(dev)=doc
|
||||
__return__ = dev.read()
|
||||
except Exception as e:
|
||||
__exception__ = e
|
||||
elif msg=="write":
|
||||
try:
|
||||
(dev, value)=doc
|
||||
dev.write(value)
|
||||
__return__ = True
|
||||
except Exception as e:
|
||||
__exception__ = e
|
||||
except Exception as e:
|
||||
#print (e)
|
||||
pass
|
||||
|
||||
|
||||
def check_pause():
|
||||
try:
|
||||
global RE, re_scan, is_scan_paused
|
||||
if CAN_PAUSE:
|
||||
if ("RE" in globals()) and (re_scan is not None) and not (re_scan.scan.isCompleted()):
|
||||
is_scan_paused =re_scan.scan.isPaused() and not re_scan.scan.isAborted()
|
||||
else:
|
||||
is_scan_paused = False
|
||||
#if re_scan.scan.isAborted():
|
||||
# if RE.state not in ['idle','paused', 'pausing']:
|
||||
# print ("Scan abort")
|
||||
# RE.abort("Scan abort")
|
||||
"""
|
||||
if re_scan.scan.isPaused():
|
||||
if RE.state not in ['idle','paused', 'pausing']:
|
||||
print ("Scan paused: Run Engine pause request")
|
||||
RE.request_pause()
|
||||
is_scan_paused = True
|
||||
else:
|
||||
if RE.state in ['paused', 'pausing']:
|
||||
print ("Scan resumed: Run Engine resuming")
|
||||
#RE.resume()
|
||||
"""
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
class ReaderWrapper():
|
||||
def __init__(self, dev):
|
||||
self.dev=dev
|
||||
self.name=dev.getName()
|
||||
self.parent = None
|
||||
try:
|
||||
self.source = self.dev.getChannelName()
|
||||
except:
|
||||
self.source = "Unknown"
|
||||
try:
|
||||
try:
|
||||
self.shape = [self.dev.getHeight(), self.dev.getWidth()]
|
||||
self.shape_str = "["+str(self.shape[0])+"]"+"["+str(self.shape[1])+"]"
|
||||
except:
|
||||
self.shape = [self.dev.getSize()]
|
||||
self.shape_str = "["+str(self.shape[0])+"]"
|
||||
except:
|
||||
self.shape = []
|
||||
self.shape_str=""
|
||||
try:
|
||||
self.precision = self.dev.getPrecision()
|
||||
except:
|
||||
self.precision = None
|
||||
self.description = {self.name: { \
|
||||
'dtype':'number', \
|
||||
'shape': self.shape, \
|
||||
'source': self.source, \
|
||||
'precision': self.precision \
|
||||
}}
|
||||
|
||||
self.cfg_description = {"shape_str":{"dtype":"string", 'shape':(len(self.shape_str),), "source":""}, }
|
||||
self.configuration = {"shape_str":{"value":self.shape_str, "timestamp":time.time()}}
|
||||
self.name = self.name+self.shape_str
|
||||
|
||||
def read(self):
|
||||
if is_main_thread():
|
||||
return {self.name:{"value":self.dev.read(), "timestamp":time.time()}}
|
||||
global __return__,__exception__
|
||||
__return__ = __exception__ = None
|
||||
handler.queue.append(("read", (self.dev)))
|
||||
while (__return__ is None) and (__exception__ is None):
|
||||
time.sleep(0.01)
|
||||
if __exception__ is not None:
|
||||
raise __exception__
|
||||
return {self.name:{"value":__return__, "timestamp":time.time()}}
|
||||
|
||||
def describe(self):
|
||||
return self.description
|
||||
|
||||
def describe_configuration(self):
|
||||
return self.cfg_description
|
||||
|
||||
def read_configuration(self):
|
||||
return self.configuration
|
||||
|
||||
class NullStatus:
|
||||
"a simple Status object that is always immediately done"
|
||||
def __init__(self):
|
||||
self._cb = None
|
||||
self.done = True
|
||||
self.success = True
|
||||
|
||||
@property
|
||||
def finished_cb(self):
|
||||
return self._cb
|
||||
|
||||
@finished_cb.setter
|
||||
def finished_cb(self, cb):
|
||||
cb()
|
||||
self._cb = cb
|
||||
|
||||
class MoverWrapper(ReaderWrapper):
|
||||
def set(self, value):
|
||||
if is_main_thread():
|
||||
self.dev.write(value)
|
||||
else:
|
||||
global __return__,__exception__
|
||||
__return__ = __exception__ = None
|
||||
handler.queue.append(("write", (self.dev, value)))
|
||||
while (__return__ is None) and (__exception__ is None):
|
||||
time.sleep(0.01)
|
||||
if __exception__ is not None:
|
||||
raise __exception__
|
||||
self.dev.waitReady(-1)
|
||||
return NullStatus()
|
||||
|
||||
@property
|
||||
def position(self):
|
||||
return self.dev.getPosition()
|
||||
|
||||
def stop(self, *, success=False):
|
||||
self.dev.stop()
|
||||
|
||||
|
||||
|
||||
RE = RunEngine({}, during_task=EventProcessingTask())
|
||||
if CAN_PAUSE:
|
||||
RE.pause_msg="User abort"
|
||||
bec = BestEffortCallback()
|
||||
bec.disable_plots()
|
||||
RE.subscribe(bec)
|
||||
RE.subscribe(handler)
|
||||
|
||||
motor.delay = 1.1 # simulate slow motor movement
|
||||
ch1 = EpicsSignal("TESTIOC:TESTSINUS:SinCalc")
|
||||
#TODO: DEmonstrate use of waveform and areadetector (Manual scan setup with the indexes in name)
|
||||
#ch2 = EpicsSignal("TESTIOC:TESTWF2:MyWF", name="arr[10]")
|
||||
#ch3 = EpicsSignal("TESTIOC:TESTWF2:MyWF", name="img[3][2]")det3=ReaderWrapper(sin)
|
||||
dets = [det1, det2]
|
||||
Reference in New Issue
Block a user