docs: reviewed docstrings
This commit is contained in:
parent
6780c523bd
commit
d295741bd0
@ -20,15 +20,20 @@ logger = bec_logger.logger
|
|||||||
|
|
||||||
|
|
||||||
class DelayGeneratorError(Exception):
|
class DelayGeneratorError(Exception):
|
||||||
"""Exception raised for errors in the Delay Generator."""
|
"""Exception raised for errors."""
|
||||||
|
|
||||||
|
|
||||||
class DeviceInitError(DelayGeneratorError):
|
class DeviceInitError(DelayGeneratorError):
|
||||||
"""Error raised when init of device class fails due to missing device manager or not started in sim_mode."""
|
"""Error upon failed initialization, invoked by missing device manager or device not started in sim_mode."""
|
||||||
|
|
||||||
|
|
||||||
|
class DelayGeneratorNotOkay(DelayGeneratorError):
|
||||||
|
"""Error when DDG is not okay"""
|
||||||
|
|
||||||
|
|
||||||
class DelayStatic(Device):
|
class DelayStatic(Device):
|
||||||
"""Static axis for the T0 output channel
|
"""
|
||||||
|
Static axis for the T0 output channel
|
||||||
|
|
||||||
It allows setting the logic levels, but the timing is fixed.
|
It allows setting the logic levels, but the timing is fixed.
|
||||||
The signal is high after receiving the trigger until the end
|
The signal is high after receiving the trigger until the end
|
||||||
@ -62,7 +67,7 @@ class DelayStatic(Device):
|
|||||||
|
|
||||||
|
|
||||||
class DummyPositioner(PVPositioner):
|
class DummyPositioner(PVPositioner):
|
||||||
"""Dummy positioner for the DG645"""
|
"""Dummy Positioner to set AO, AI and ReferenceMO."""
|
||||||
|
|
||||||
setpoint = Component(EpicsSignal, "DelayAO", put_complete=True, kind=Kind.config)
|
setpoint = Component(EpicsSignal, "DelayAO", put_complete=True, kind=Kind.config)
|
||||||
readback = Component(EpicsSignalRO, "DelayAI", kind=Kind.config)
|
readback = Component(EpicsSignalRO, "DelayAI", kind=Kind.config)
|
||||||
@ -71,10 +76,11 @@ class DummyPositioner(PVPositioner):
|
|||||||
|
|
||||||
|
|
||||||
class DelayPair(PseudoPositioner):
|
class DelayPair(PseudoPositioner):
|
||||||
"""Delay pair interface for DG645
|
"""
|
||||||
|
Delay pair interface
|
||||||
|
|
||||||
Virtual motor interface to a pair of signals (on the frontpanel).
|
Virtual motor interface to a pair of signals (on the frontpanel - AB/CD/EF/GH).
|
||||||
It offers a simple delay and pulse width interface for scanning.
|
It offers a simple delay and pulse width interface.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The pseudo positioner axes
|
# The pseudo positioner axes
|
||||||
@ -107,10 +113,15 @@ class DelayPair(PseudoPositioner):
|
|||||||
|
|
||||||
class DDGCustomMixin:
|
class DDGCustomMixin:
|
||||||
"""
|
"""
|
||||||
Mixin class for custom DelayGenerator logic
|
Mixin class for custom DelayGenerator logic within PSIDelayGeneratorBase.
|
||||||
|
|
||||||
This class is used to implement BL specific logic for the DDG.
|
This class provides a parent class for implementation of BL specific logic of the device.
|
||||||
It is used in the PSIDelayGeneratorBase class.
|
It is also possible to pass implementing certain methods, e.g. finished or on_trigger,
|
||||||
|
based on the setup and desired operation mode at the beamline.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
parent (object): instance of PSIDelayGeneratorBase
|
||||||
|
**kwargs: keyword arguments
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *_args, parent: Device = None, **_kwargs) -> None:
|
def __init__(self, *_args, parent: Device = None, **_kwargs) -> None:
|
||||||
@ -118,41 +129,48 @@ class DDGCustomMixin:
|
|||||||
|
|
||||||
def initialize_default_parameter(self) -> None:
|
def initialize_default_parameter(self) -> None:
|
||||||
"""
|
"""
|
||||||
Initialize default parameters for DDG
|
Method to initialize default parameters for DDG.
|
||||||
|
|
||||||
This method is called upon initiating the class.
|
Called upon initiating the base class.
|
||||||
It can be conveniently used to set default parameters for the DDG.
|
It should be used to set the DDG default parameters.
|
||||||
These may include, amplitudes, offsets, delays, etc.
|
These may include: amplitude, offsets, delays, etc.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def prepare_ddg(self) -> None:
|
def prepare_ddg(self) -> None:
|
||||||
"""
|
"""
|
||||||
Prepare the DDG for the upcoming scan
|
Method to prepare the DDG for the upcoming scan.
|
||||||
|
|
||||||
This methods hosts the full logic for the upcoming scan.
|
Called by the stage method of the base class.
|
||||||
It is called by the stage method and needs to fully prepare the DDGs for the upcoming scan.
|
It should be used to set the DDG parameters for the upcoming scan.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def on_trigger(self) -> None:
|
def on_trigger(self) -> None:
|
||||||
"""Define action executed on trigger methods"""
|
"""Method executed upon trigger call in parent class"""
|
||||||
|
|
||||||
def finished(self) -> None:
|
def finished(self) -> None:
|
||||||
"""Checks if DDG finished acquisition"""
|
"""Method to check if DDG is finished with the scan"""
|
||||||
|
|
||||||
def on_pre_scan(self) -> None:
|
def on_pre_scan(self) -> None:
|
||||||
"""
|
"""
|
||||||
Called by pre scan hook
|
Method executed upon pre_scan call in parent class.
|
||||||
|
|
||||||
These actions get executed just before the trigger method/start of scan
|
Covenient to implement time sensitive actions to be executed right before start of the scan.
|
||||||
|
Example could be to open the shutter by triggering a pulse via pre_scan.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def check_scanID(self) -> None:
|
def check_scanID(self) -> None:
|
||||||
"""
|
"""Method to check if there is a new scanID, called by stage."""
|
||||||
Check if BEC is running on a new scanID
|
|
||||||
"""
|
|
||||||
|
|
||||||
def is_ddg_okay(self, raise_on_error=False) -> None:
|
def is_ddg_okay(self, raise_on_error=False) -> None:
|
||||||
"""Check if DDG is okay, if not try to clear error"""
|
"""
|
||||||
|
Method to check if DDG is okay
|
||||||
|
|
||||||
|
It checks the status PV of the DDG and tries to clear the error if it is not okay.
|
||||||
|
It will rerun itself and raise DelayGeneratorNotOkay if DDG is still not okay.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
raise_on_error (bool, optional): raise exception if DDG is not okay. Defaults to False.
|
||||||
|
"""
|
||||||
status = self.parent.status.read()[self.parent.status.name]["value"]
|
status = self.parent.status.read()[self.parent.status.name]["value"]
|
||||||
if status != "STATUS OK" and not raise_on_error:
|
if status != "STATUS OK" and not raise_on_error:
|
||||||
logger.warning(f"DDG returns {status}, trying to clear ERROR")
|
logger.warning(f"DDG returns {status}, trying to clear ERROR")
|
||||||
@ -160,7 +178,7 @@ class DDGCustomMixin:
|
|||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
self.is_ddg_okay(raise_on_error=True)
|
self.is_ddg_okay(raise_on_error=True)
|
||||||
elif status != "STATUS OK":
|
elif status != "STATUS OK":
|
||||||
raise Exception(f"DDG failed to start with status: {status}")
|
raise DelayGeneratorNotOkay(f"DDG failed to start with status: {status}")
|
||||||
|
|
||||||
|
|
||||||
class PSIDelayGeneratorBase(Device):
|
class PSIDelayGeneratorBase(Device):
|
||||||
@ -170,14 +188,16 @@ class PSIDelayGeneratorBase(Device):
|
|||||||
This class implements a thin Ophyd wrapper around the Stanford Research DG645
|
This class implements a thin Ophyd wrapper around the Stanford Research DG645
|
||||||
digital delay generator.
|
digital delay generator.
|
||||||
|
|
||||||
Internally, the DG645 generates 8+1 signals: A, B, C, D, E, F, G, H and T0
|
The DG645 generates 8+1 signals: A, B, C, D, E, F, G, H and T0. Front panel outputs
|
||||||
Front panel outputs T0, AB, CD, EF and GH are a combination of these signals.
|
T0, AB, CD, EF and GH are combinations of these signals. Back panel outputs are
|
||||||
Back panel outputs are directly routed signals. So signals are NOT INDEPENDENT.
|
directly routed signals. Signals are not independent.
|
||||||
|
|
||||||
Front panel signals:
|
Signal pairs, e.g. AB, CD, EF, GH, are implemented as DelayPair objects. They
|
||||||
All signals go high after their defined delays and go low after the trigger
|
have a TTL pulse width, delay and a reference signal to which they are being triggered.
|
||||||
holdoff period, i.e. this is the trigger window. Front panel outputs provide
|
In addition, the io layer allows setting amplitude, offset and polarity for each pair.
|
||||||
a combination of these events.
|
|
||||||
|
Detailed information can be found in the manual:
|
||||||
|
https://www.thinksrs.com/downloads/pdfs/manuals/DG645m.pdf
|
||||||
|
|
||||||
Class attributes:
|
Class attributes:
|
||||||
custom_prepare_cls (object): class for custom prepare logic (BL specific)
|
custom_prepare_cls (object): class for custom prepare logic (BL specific)
|
||||||
@ -196,7 +216,6 @@ class PSIDelayGeneratorBase(Device):
|
|||||||
device_manager (object) : bec device manager
|
device_manager (object) : bec device manager
|
||||||
sim_mode (bool) : simulation mode, if True, no device manager is required
|
sim_mode (bool) : simulation mode, if True, no device manager is required
|
||||||
**kwargs : keyword arguments
|
**kwargs : keyword arguments
|
||||||
|
|
||||||
attributes : lazy_wait_for_connection : bool
|
attributes : lazy_wait_for_connection : bool
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -215,6 +234,7 @@ class PSIDelayGeneratorBase(Device):
|
|||||||
"reload_config",
|
"reload_config",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Assign PVs from DDG645
|
||||||
trigger_burst_readout = Component(
|
trigger_burst_readout = Component(
|
||||||
EpicsSignal, "EventStatusLI.PROC", name="trigger_burst_readout"
|
EpicsSignal, "EventStatusLI.PROC", name="trigger_burst_readout"
|
||||||
)
|
)
|
||||||
@ -230,7 +250,6 @@ class PSIDelayGeneratorBase(Device):
|
|||||||
channelEF = Component(DelayPair, "", name="EF", channel="EF")
|
channelEF = Component(DelayPair, "", name="EF", channel="EF")
|
||||||
channelGH = Component(DelayPair, "", name="GH", channel="GH")
|
channelGH = Component(DelayPair, "", name="GH", channel="GH")
|
||||||
|
|
||||||
# Minimum time between triggers
|
|
||||||
holdoff = Component(
|
holdoff = Component(
|
||||||
EpicsSignal,
|
EpicsSignal,
|
||||||
"TriggerHoldoffAI",
|
"TriggerHoldoffAI",
|
||||||
@ -267,7 +286,6 @@ class PSIDelayGeneratorBase(Device):
|
|||||||
kind=Kind.config,
|
kind=Kind.config,
|
||||||
)
|
)
|
||||||
trigger_shot = Component(EpicsSignal, "TriggerDelayBO", name="trigger_shot", kind="config")
|
trigger_shot = Component(EpicsSignal, "TriggerDelayBO", name="trigger_shot", kind="config")
|
||||||
# Burst mode
|
|
||||||
burstMode = Component(
|
burstMode = Component(
|
||||||
EpicsSignal,
|
EpicsSignal,
|
||||||
"BurstModeBI",
|
"BurstModeBI",
|
||||||
@ -359,27 +377,30 @@ class PSIDelayGeneratorBase(Device):
|
|||||||
self.custom_prepare.is_ddg_okay()
|
self.custom_prepare.is_ddg_okay()
|
||||||
|
|
||||||
def _update_scaninfo(self) -> None:
|
def _update_scaninfo(self) -> None:
|
||||||
"""Update scaninfo from BecScaninfoMixing
|
"""
|
||||||
This depends on device manager and operation/sim_mode
|
Method to updated scaninfo from BEC.
|
||||||
|
|
||||||
|
In sim_mode, scaninfo output is mocked - see bec_scaninfo_mixin.py
|
||||||
"""
|
"""
|
||||||
self.scaninfo = BecScaninfoMixin(self.device_manager, self.sim_mode)
|
self.scaninfo = BecScaninfoMixin(self.device_manager, self.sim_mode)
|
||||||
self.scaninfo.load_scan_metadata()
|
self.scaninfo.load_scan_metadata()
|
||||||
|
|
||||||
def _init(self) -> None:
|
def _init(self) -> None:
|
||||||
"""Initialize detector, filewriter and set default parameters"""
|
"""Method to initialize custom parameters of the DDG."""
|
||||||
self.custom_prepare.initialize_default_parameter()
|
self.custom_prepare.initialize_default_parameter()
|
||||||
|
|
||||||
def set_channels(self, signal: str, value: Any, channels: List = None) -> None:
|
def set_channels(self, signal: str, value: Any, channels: List = None) -> None:
|
||||||
"""
|
"""
|
||||||
Sets value on signal in list all_channels
|
Method to set signals on DelayPair and DelayStatic channels.
|
||||||
|
|
||||||
Setting values works on DelayPair and DelayStatic channels.
|
Signals can be set on the DelayPair and DelayStatic channels. The method checks
|
||||||
|
if the signal is available on the channel and sets it. It works for both, DelayPair
|
||||||
|
and Delay Static although signals are hosted in different layers.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
signal (str): signal to set
|
signal (str) : signal to set (width, delay, amplitude, offset, polarity)
|
||||||
value (Any) : value to set
|
value (Any) : value to set
|
||||||
channels (List, optional): list of channels to set. Defaults to self.all_channels.
|
channels (List, optional) : list of channels to set. Defaults to self.all_channels (T0,AB,CD,EF,GH)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not channels:
|
if not channels:
|
||||||
channels = self.all_channels
|
channels = self.all_channels
|
||||||
@ -395,17 +416,18 @@ class PSIDelayGeneratorBase(Device):
|
|||||||
|
|
||||||
def stage(self) -> List[object]:
|
def stage(self) -> List[object]:
|
||||||
"""
|
"""
|
||||||
Stage device in preparation for a scan
|
Method to stage the device.
|
||||||
|
|
||||||
|
Called in preparation for a scan.
|
||||||
|
|
||||||
Internal Calls:
|
Internal Calls:
|
||||||
- scaninfo.load_scan_metadata : load scan metadata
|
- scaninfo.load_scan_metadata : load scan metadata
|
||||||
- custom_prepare.prepare_ddg : prepare DDG for measurement
|
- custom_prepare.prepare_ddg : prepare DDG for measurement
|
||||||
|
- is_ddg_okay : check if DDG is okay
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List(object): list of objects that were staged
|
List(object): list of objects that were staged
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Method idempotent, should rais ;obj;'RedudantStaging' if staged twice
|
|
||||||
if self._staged != Staged.no:
|
if self._staged != Staged.no:
|
||||||
return super().stage()
|
return super().stage()
|
||||||
self.stopped = False
|
self.stopped = False
|
||||||
@ -418,25 +440,35 @@ class PSIDelayGeneratorBase(Device):
|
|||||||
return super().stage()
|
return super().stage()
|
||||||
|
|
||||||
def trigger(self) -> DeviceStatus:
|
def trigger(self) -> DeviceStatus:
|
||||||
"""Trigger the detector, called from BEC."""
|
"""
|
||||||
|
Method to trigger the acquisition.
|
||||||
|
|
||||||
|
Internal Call:
|
||||||
|
- custom_prepare.on_trigger : execute BL specific action
|
||||||
|
"""
|
||||||
self.custom_prepare.on_trigger()
|
self.custom_prepare.on_trigger()
|
||||||
return super().trigger()
|
return super().trigger()
|
||||||
|
|
||||||
def pre_scan(self) -> None:
|
def pre_scan(self) -> None:
|
||||||
"""Pre scan hook, called before the scan starts"""
|
"""
|
||||||
|
Method pre_scan gets executed directly before the scan
|
||||||
|
|
||||||
|
Internal Call:
|
||||||
|
- custom_prepare.on_pre_scan : execute BL specific action
|
||||||
|
"""
|
||||||
self.custom_prepare.on_pre_scan()
|
self.custom_prepare.on_pre_scan()
|
||||||
|
|
||||||
def unstage(self) -> List[object]:
|
def unstage(self) -> List[object]:
|
||||||
"""
|
"""
|
||||||
Unstage device in preparation for a scan
|
Method unstage gets called at the end of a scan.
|
||||||
|
|
||||||
Returns directly if self.stopped,
|
If scan (self.stopped is True) is stopped, returns directly.
|
||||||
otherwise checks with self._finished
|
Otherwise, checks if the DDG finished acquisition
|
||||||
if data acquisition on device finished (an was successful)
|
|
||||||
|
|
||||||
Internal Calls:
|
Internal Calls:
|
||||||
- custom_prepare.check_scanID : check if scanID changed or detector stopped
|
- custom_prepare.check_scanID : check if scanID changed or detector stopped
|
||||||
- custom_prepare.finished : check if device finished acquisition (succesfully)
|
- custom_prepare.finished : check if device finished acquisition (succesfully)
|
||||||
|
- is_ddg_okay : check if DDG is okay
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List(object): list of objects that were unstaged
|
List(object): list of objects that were unstaged
|
||||||
@ -451,9 +483,12 @@ class PSIDelayGeneratorBase(Device):
|
|||||||
|
|
||||||
def stop(self, *, success=False) -> None:
|
def stop(self, *, success=False) -> None:
|
||||||
"""
|
"""
|
||||||
Stop the DDG
|
Method to stop the DDG
|
||||||
|
|
||||||
#TODO check if the pulse sequence can be stopped, which PV should be called?
|
#TODO Check if the pulse generation can be interruppted
|
||||||
|
|
||||||
|
Internal Call:
|
||||||
|
- custom_prepare.is_ddg_okay : check if DDG is okay
|
||||||
"""
|
"""
|
||||||
self.custom_prepare.is_ddg_okay()
|
self.custom_prepare.is_ddg_okay()
|
||||||
super().stop(success=success)
|
super().stop(success=success)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user