Skip to content

Commit cc13bbb

Browse files
committed
fixes #267
1 parent 792b88f commit cc13bbb

File tree

1 file changed

+115
-110
lines changed

1 file changed

+115
-110
lines changed

apstools/plans.py

Lines changed: 115 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,12 @@
4040
import sys
4141
import time
4242

43-
from bluesky import preprocessors as bpp
43+
from bluesky import plans as bp
4444
from bluesky import plan_stubs as bps
45+
from bluesky import preprocessors as bpp
4546
from bluesky.callbacks.fitting import PeakStats
4647
from ophyd import Device, Component, Signal, DeviceStatus, EpicsSignal
48+
from ophyd.scaler import ScalerCH, ScalerChannel
4749
from ophyd.status import Status
4850

4951
from . import utils as APS_utils
@@ -252,125 +254,128 @@ def _internal(blocking_function, *args, **kwargs):
252254
return status
253255

254256

255-
def lineup(
256-
counter, axis, minus, plus, npts,
257-
time_s=0.1, peak_factor=4, width_factor=0.8,
258-
_md={}):
259-
"""
260-
lineup and center a given axis, relative to current position
257+
# TODO: the lineup() plan needs access to the BestEffortCallbacks().peaks object.
258+
# 2019-12-03,prj: removing until we can get to that object (if it even exists) from here
259+
#-----
260+
# def lineup(
261+
# counter, axis, minus, plus, npts,
262+
# time_s=0.1, peak_factor=4, width_factor=0.8,
263+
# _md={}):
264+
# """
265+
# lineup and center a given axis, relative to current position
261266

262-
PARAMETERS
267+
# PARAMETERS
263268

264-
counter : object
265-
instance of ophyd.Signal (or subclass such as ophyd.scaler.ScalerChannel)
266-
dependent measurement to be maximized
269+
# counter : object
270+
# instance of ophyd.Signal (or subclass such as ophyd.scaler.ScalerChannel)
271+
# dependent measurement to be maximized
267272

268-
axis : movable object
269-
instance of ophyd.Signal (or subclass such as EpicsMotor)
270-
independent axis to use for alignment
273+
# axis : movable object
274+
# instance of ophyd.Signal (or subclass such as EpicsMotor)
275+
# independent axis to use for alignment
271276

272-
minus : float
273-
first point of scan at this offset from starting position
277+
# minus : float
278+
# first point of scan at this offset from starting position
274279

275-
plus : float
276-
last point of scan at this offset from starting position
280+
# plus : float
281+
# last point of scan at this offset from starting position
277282

278-
npts : int
279-
number of data points in the scan
283+
# npts : int
284+
# number of data points in the scan
280285

281-
time_s : float (default: 0.1)
282-
count time per step (if counter is ScalerChannel object)
286+
# time_s : float (default: 0.1)
287+
# count time per step (if counter is ScalerChannel object)
283288

284-
peak_factor : float (default: 4)
285-
maximum must be greater than 'peak_factor'*minimum
289+
# peak_factor : float (default: 4)
290+
# maximum must be greater than 'peak_factor'*minimum
286291

287-
width_factor : float (default: 0.8)
288-
fwhm must be less than 'width_factor'*plot_range
289-
290-
EXAMPLE:
291-
292-
RE(lineup(diode, foemirror.theta, -30, 30, 30, 1.0))
293-
"""
294-
# first, determine if counter is part of a ScalerCH device
295-
scaler = None
296-
obj = counter.parent
297-
if isinstance(counter.parent, ScalerChannel):
298-
if hasattr(obj, "parent") and obj.parent is not None:
299-
obj = obj.parent
300-
if hasattr(obj, "parent") and isinstance(obj.parent, ScalerCH):
301-
scaler = obj.parent
302-
303-
if scaler is not None:
304-
old_sigs = scaler.stage_sigs
305-
scaler.stage_sigs["preset_time"] = time_s
306-
scaler.select_channels([counter.name])
307-
308-
if hasattr(axis, "position"):
309-
old_position = axis.position
310-
else:
311-
old_position = axis.value
312-
313-
def peak_analysis():
314-
aligned = False
315-
if counter.name in bec.peaks["cen"]:
316-
table = pyRestTable.Table()
317-
table.labels = ("key", "value")
318-
table.addRow(("axis", axis.name))
319-
table.addRow(("detector", counter.name))
320-
table.addRow(("starting position", old_position))
321-
for key in bec.peaks.ATTRS:
322-
table.addRow((key, bec.peaks[key][counter.name]))
323-
logger.info(f"alignment scan results:\n{table}")
324-
325-
lo = bec.peaks["min"][counter.name][-1] # [-1] means detector
326-
hi = bec.peaks["max"][counter.name][-1] # [0] means axis
327-
fwhm = bec.peaks["fwhm"][counter.name]
328-
final = bec.peaks["cen"][counter.name]
329-
330-
ps = list(bec._peak_stats.values())[0][counter.name] # PeakStats object
331-
# get the X data range as received by PeakStats
332-
x_range = abs(max(ps.x_data) - min(ps.x_data))
333-
334-
if final is None:
335-
logger.error(f"centroid is None")
336-
final = old_position
337-
elif fwhm is None:
338-
logger.error(f"FWHM is None")
339-
final = old_position
340-
elif hi < peak_factor*lo:
341-
logger.error(f"no clear peak: {hi} < {peak_factor}*{lo}")
342-
final = old_position
343-
elif fwhm > width_factor*x_range:
344-
logger.error(f"FWHM too large: {fwhm} > {width_factor}*{x_range}")
345-
final = old_position
346-
else:
347-
aligned = True
292+
# width_factor : float (default: 0.8)
293+
# fwhm must be less than 'width_factor'*plot_range
294+
295+
# EXAMPLE:
296+
297+
# RE(lineup(diode, foemirror.theta, -30, 30, 30, 1.0))
298+
# """
299+
# # first, determine if counter is part of a ScalerCH device
300+
# scaler = None
301+
# obj = counter.parent
302+
# if isinstance(counter.parent, ScalerChannel):
303+
# if hasattr(obj, "parent") and obj.parent is not None:
304+
# obj = obj.parent
305+
# if hasattr(obj, "parent") and isinstance(obj.parent, ScalerCH):
306+
# scaler = obj.parent
307+
308+
# if scaler is not None:
309+
# old_sigs = scaler.stage_sigs
310+
# scaler.stage_sigs["preset_time"] = time_s
311+
# scaler.select_channels([counter.name])
312+
313+
# if hasattr(axis, "position"):
314+
# old_position = axis.position
315+
# else:
316+
# old_position = axis.value
317+
318+
# def peak_analysis():
319+
# aligned = False
320+
# if counter.name in bec.peaks["cen"]:
321+
# table = pyRestTable.Table()
322+
# table.labels = ("key", "value")
323+
# table.addRow(("axis", axis.name))
324+
# table.addRow(("detector", counter.name))
325+
# table.addRow(("starting position", old_position))
326+
# for key in bec.peaks.ATTRS:
327+
# table.addRow((key, bec.peaks[key][counter.name]))
328+
# logger.info(f"alignment scan results:\n{table}")
329+
330+
# lo = bec.peaks["min"][counter.name][-1] # [-1] means detector
331+
# hi = bec.peaks["max"][counter.name][-1] # [0] means axis
332+
# fwhm = bec.peaks["fwhm"][counter.name]
333+
# final = bec.peaks["cen"][counter.name]
334+
335+
# ps = list(bec._peak_stats.values())[0][counter.name] # PeakStats object
336+
# # get the X data range as received by PeakStats
337+
# x_range = abs(max(ps.x_data) - min(ps.x_data))
338+
339+
# if final is None:
340+
# logger.error(f"centroid is None")
341+
# final = old_position
342+
# elif fwhm is None:
343+
# logger.error(f"FWHM is None")
344+
# final = old_position
345+
# elif hi < peak_factor*lo:
346+
# logger.error(f"no clear peak: {hi} < {peak_factor}*{lo}")
347+
# final = old_position
348+
# elif fwhm > width_factor*x_range:
349+
# logger.error(f"FWHM too large: {fwhm} > {width_factor}*{x_range}")
350+
# final = old_position
351+
# else:
352+
# aligned = True
348353

349-
logger.info(f"moving {axis.name} to {final} (aligned: {aligned})")
350-
yield from bps.mv(axis, final)
351-
else:
352-
logger.error("no statistical analysis of scan peak!")
353-
yield from bps.null()
354-
355-
# too sneaky? We're modifying this structure locally
356-
bec.peaks.aligned = aligned
357-
bec.peaks.ATTRS = ('com', 'cen', 'max', 'min', 'fwhm')
358-
359-
md = dict(_md)
360-
md["purpose"] = "alignment"
361-
yield from bp.rel_scan([counter], axis, minus, plus, npts, md=md)
362-
yield from peak_analysis()
363-
364-
if bec.peaks.aligned:
365-
# again, tweak axis to maximize
366-
md["purpose"] = "alignment - fine"
367-
fwhm = bec.peaks["fwhm"][counter.name]
368-
yield from bp.rel_scan([counter], axis, -fwhm, fwhm, npts, md=md)
369-
yield from peak_analysis()
370-
371-
if scaler is not None:
372-
scaler.select_channels()
373-
scaler.stage_sigs = old_sigs
354+
# logger.info(f"moving {axis.name} to {final} (aligned: {aligned})")
355+
# yield from bps.mv(axis, final)
356+
# else:
357+
# logger.error("no statistical analysis of scan peak!")
358+
# yield from bps.null()
359+
360+
# # too sneaky? We're modifying this structure locally
361+
# bec.peaks.aligned = aligned
362+
# bec.peaks.ATTRS = ('com', 'cen', 'max', 'min', 'fwhm')
363+
364+
# md = dict(_md)
365+
# md["purpose"] = "alignment"
366+
# yield from bp.rel_scan([counter], axis, minus, plus, npts, md=md)
367+
# yield from peak_analysis()
368+
369+
# if bec.peaks.aligned:
370+
# # again, tweak axis to maximize
371+
# md["purpose"] = "alignment - fine"
372+
# fwhm = bec.peaks["fwhm"][counter.name]
373+
# yield from bp.rel_scan([counter], axis, -fwhm, fwhm, npts, md=md)
374+
# yield from peak_analysis()
375+
376+
# if scaler is not None:
377+
# scaler.select_channels()
378+
# scaler.stage_sigs = old_sigs
374379

375380

376381
def nscan(detectors, *motor_sets, num=11, per_step=None, md=None):

0 commit comments

Comments
 (0)