ophyd
ophyd copied to clipboard
EpicsMCA Ophyd Device reports triggering from sucess before it's complete after staging
Problem was seen when trying to use the EpicsMCA ophyd device with a scan plan. The mca device is a Bruker/Rontec.
RE(count([mca]))
results in the device being staged, and triggered, and then immediately reading, rather than waiting for the status object of the trigger method to report sucess.
If the trigger method is called outside of the RE without staging like mca.trigger()
then the status object reports done correctly once the record has finished processing.
If the device is first staged, and then triggered, then the status object returned by the trigger() method already reports sucess.
Removing everything from mca.stage_sigs and mca.configuration_attrs does not fix the problem.
Here is the output with trace messages from the runengin
17:18:45.738100 stage -> bruker args: (), kwargs: {}, run: None
17:18:45.739458 open_run -> None args: (), kwargs: {'detectors': ['bruker'], 'num_points': 1, 'num_intervals': 0, 'plan_args': {'detectors': ["EpicsMCA(prefix='SISSY2EX:SDD00:mca1', name='bruker', read_attrs=['preset_real_time', 'elapsed_real_time', 'spectrum'], configuration_attrs=[])"], 'num': 1}, 'plan_name': 'count', 'hints': {'dimensions': [(('time',), 'primary')]}}, run: None
Transient Scan ID: 1 Time: 2021-10-04 17:18:45
Persistent Unique Scan ID: 'a00b7e32-987f-443d-a778-0fea556edcc8'
17:18:45.745888 checkpoint -> None args: (), kwargs: {}, run: None
17:18:45.746267 checkpoint -> None args: (), kwargs: {}, run: None
17:18:45.746700 trigger -> bruker args: (), kwargs: {'group': 'trigger-36101d'}, run: None
17:18:45.747916 wait -> None args: (), kwargs: {'group': 'trigger-36101d'}, run: None
17:18:45.748928 create -> None args: (), kwargs: {'name': 'primary'}, run: None
17:18:45.749229 read -> bruker args: (), kwargs: {}, run: None
17:18:45.751733 save -> None args: (), kwargs: {}, run: None
New stream: 'primary'
+-----------+------------+
| seq_num | time |
+-----------+------------+
| 1 | 17:18:45.7 |
17:18:45.755403 close_run -> None args: (), kwargs: {'exit_status': None, 'reason': None}, run: None
+-----------+------------+
generator count ['a00b7e32'] (scan num: 1)
17:18:45.858398 unstage -> bruker args: (), kwargs: {}, run: None
('a00b7e32-987f-443d-a778-0fea556edcc8',)
I have a workaround for the moment which rewrites the trigger method to consider other fields than just the callback from the erase_start signal.
class MyEpicsMCA(EpicsMCA):
#redefine erase_start so that it's no longer in self.trigger_signals
erase_start = Cpt(EpicsSignal, 'EraseStart', kind='omitted')
#Add the PV that monitors when acquisition is complete
acquiring = Cpt(EpicsSignalRO, '.ACQG', kind='omitted')
def trigger(self):
callback_signal = self.acquiring
#variable used as an event flag
acquisition_status = False
def acquisition_started(status):
nonlocal acquisition_status #Define as nonlocal as we want to modify it
acquisition_status = True
def check_value(*, old_value, value, **kwargs):
#Return True when the acquisition is complete, False otherwise.
if not acquisition_status: #But only report done if acquisition was already started
return False
return (value == 0 and old_value == 1 and self.preset_real_time.get() == self.elapsed_real_time.get())
# create the status with SubscriptionStatus that add's a callback to check_value.
sta_cnt = SubscriptionStatus(callback_signal, check_value, run=False, settle_time = 3) #Add some settle time
# Start the acquisition
sta_acq = self.erase_start.set(1)
sta_acq.add_callback(acquisition_started)
stat = AndStatus(sta_cnt, sta_acq)
return stat