Skip to content

Commit

Permalink
fix terminology to fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
henrypinkard committed Aug 22, 2024
1 parent 07ddfdc commit b7b9b21
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 27 deletions.
37 changes: 22 additions & 15 deletions src/exengine/events/detector_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ class DataAcquired(Notification[DataCoordinates]):

class ReadoutData(Stoppable, DataProducing, ExecutorEvent):
"""
Readout one or more pieces of data (e.g. images) and associated metadata from a Detector device (e.g. a camera)
Readout one or more blocks of data (e.g. images) and associated metadata from a Detector device (e.g. a camera)
Args:
data_coordinate_iterator (Iterable[DataCoordinates]): An iterator or list of DataCoordinates objects, which
specify the coordinates of the data that will be read out, should be able to provide at least num_images
elements (or indefinitely if num_images is None)
detector (Union[Detector, str]): The Detector object to read data from. Can be the object itself,
or the name of the object in the ExecutionEngine's device registry.
number (int): The number of pieces of data (e.g. images) to read out. If None, the readout will continue until
the data_coordinate_iterator is exhausted or the camera is stopped and no more images are available.
stop_on_empty (bool): If True, the readout will stop when the detector is stopped when there is not an
image available to read
num_blocks (int): The number of pieces of data (e.g. images) to read out. If None, the readout will continue until
the data_coordinate_iterator is exhausted or the Detector is stopped and no more images are available.
stop_on_empty (bool): If True, the readout will stop when the detector is stopped when there is no data
available to read
data_handler (DataHandler): The DataHandler object that will handle the data read out by this event
"""
notification_types = [DataAcquired]
Expand All @@ -37,11 +37,11 @@ def __init__(self, data_coordinates_iterator: Union[DataCoordinatesIterator,
Iterable[DataCoordinates], Iterable[Dict[str, Union[int, str]]]],
detector: Optional[Union[Detector, str]] = None,
data_handler: DataHandler = None,
number: int = None,
num_blocks: int = None,
stop_on_empty: bool = False):
super().__init__(data_coordinates_iterator=data_coordinates_iterator, data_handler=data_handler)
self.detector = detector # TODO: why does IDE not like this type hint?
self.number = number
self.num_blocks = num_blocks
self.stop_on_empty = stop_on_empty


Expand All @@ -51,7 +51,7 @@ def execute(self) -> None:
else ExecutionEngine.get_device(self.detector))
# TODO a more efficient way to do this is with callbacks from the camera
# but this is not currently implemented, at least for Micro-Manager cameras
image_counter = itertools.count() if self.number is None else range(self.number)
image_counter = itertools.count() if self.num_blocks is None else range(self.num_blocks)
for image_number, image_coordinates in zip(image_counter, self.data_coordinate_iterator):
while True:
# check if event.stop has been called
Expand All @@ -69,28 +69,35 @@ def execute(self) -> None:

class StartCapture(ExecutorEvent):
"""
Special device instruction that captures images from a camera
Special device instruction that captures images from a Detector device (e.g. a camera)
"""

def __init__(self, num_images: int, detector: Optional[Detector] = None):
def __init__(self, num_blocks: int, detector: Optional[Detector] = None):
"""
Args:
num_blocks (int): The of pieces of data to capture (i.e. images on a camera)
detector (Union[Detector, str]): The Detector object to capture images from. Can be the object itself,
or the name of the object in the ExecutionEngine's device registry. If None, it will be inferred at
runtime
"""
super().__init__()
self.num_images = num_images
self.num_blocks = num_blocks
self.detector = detector

def execute(self):
"""
Capture images from the camera
Capture images from the detector
"""
try:
self.detector.arm(self.num_images)
self.detector.arm(self.num_blocks)
self.detector.start()
except Exception as e:
self.detector.stop()
raise e

class StartContinuousCapture(ExecutorEvent):
"""
Tell data-producing device to start capturing images continuously, until a stop signal is received
Tell Detector device to start capturing images continuously, until a stop signal is received
"""

def __init__(self, camera: Optional[Detector] = None):
Expand All @@ -110,7 +117,7 @@ def execute(self):

class StopCapture(ExecutorEvent):
"""
Tell data-producing device to start capturing images continuously, until a stop signal is received
Tell Detector device to start capturing data continuously, until a stop signal is received
"""

def __init__(self, camera: Optional[Detector] = None):
Expand Down
8 changes: 4 additions & 4 deletions src/exengine/events/multi_d_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def generate_events(event_list, order, coords=None):
# ))

# Add StartCapture event
new_event_list.append(StartCapture(detector=camera, num_images=total_sequence_length))
new_event_list.append(StartCapture(detector=camera, num_blocks=total_sequence_length))

# Create data coordinates for ReadoutImages
axes_names = {"t": "time", "z": "z", "c": "channel", "p": "position"}
Expand All @@ -165,7 +165,7 @@ def generate_events(event_list, order, coords=None):

new_event_list.append(ReadoutData(
detector=camera,
number=total_sequence_length,
num_blocks=total_sequence_length,
data_coordinates_iterator=coords_iterator
))

Expand Down Expand Up @@ -219,8 +219,8 @@ def generate_events(event_list, order, coords=None):
if sequence is None:
# Non-sequenced case: Add StartCapture and ReadoutImages events
num_images = 1
event_set.append(StartCapture(detector=camera, num_images=num_images))
event_set.append(ReadoutData(detector=camera, number=num_images,
event_set.append(StartCapture(detector=camera, num_blocks=num_images))
event_set.append(ReadoutData(detector=camera, num_blocks=num_images,
data_coordinates_iterator=[DataCoordinates(**coords)]))

final_events.append(event_set)
Expand Down
16 changes: 8 additions & 8 deletions src/exengine/events/test/test_multi_d_events_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test_sequenced_z_stack():
assert isinstance(events[0], SetTriggerable1DPositionsEvent)
assert isinstance(events[1], StartCapture)
assert isinstance(events[2], ReadoutData)
assert events[1].number == 6 # 6 z-positions
assert events[1].num_blocks == 6 # 6 z-positions


def test_sequenced_timelapse():
Expand All @@ -58,11 +58,11 @@ def test_sequenced_timelapse():

# Check the SetTriggerablePropertySequencesEvent
# Check the StartCapture event
assert events[0].number == num_time_points
assert events[0].num_blocks == num_time_points

# Check the ReadoutImages event
readout_event = events[1]
assert readout_event.number == num_time_points
assert readout_event.num_blocks == num_time_points

# Check the data coordinate iterator
coords = list(readout_event.data_coordinate_iterator)
Expand Down Expand Up @@ -95,7 +95,7 @@ def test_sequenced_channels():
assert isinstance(events[0], SetTriggerablePropertySequencesEvent)
assert isinstance(events[1], StartCapture)
assert isinstance(events[2], ReadoutData)
assert events[1].number == 3 # 3 channels
assert events[1].num_blocks == 3 # 3 channels


# TODO: implement channels in multi d
Expand Down Expand Up @@ -148,7 +148,7 @@ def test_sequenced_channels_and_z_stack_zc_order():
assert isinstance(events[3], ReadoutData)

# Check if the number of images is correct (6 z-positions * 2 channels)
assert events[2].number == 12
assert events[2].num_blocks == 12

# Check if the number of z-positions is correct
assert len(events[0].positions) == 12
Expand Down Expand Up @@ -190,7 +190,7 @@ def test_sequenced_channels_and_z_stack_cz_order():
assert isinstance(events[1], SetTriggerable1DPositionsEvent) or isinstance(events[0], SetTriggerable1DPositionsEvent)
assert isinstance(events[2], StartCapture)
assert isinstance(events[3], ReadoutData)
assert events[2].number == 12
assert events[2].num_blocks == 12

expected_channel_sequence = ['DAPI'] * 6 + ['FITC'] * 6
assert events[1].property_sequences[0][2] == expected_channel_sequence
Expand Down Expand Up @@ -220,7 +220,7 @@ def test_sequenced_time_channels_and_z_stack_tzc_order():
assert isinstance(events[0], SetTriggerablePropertySequencesEvent) or isinstance(events[0], SetTriggerable1DPositionsEvent)
assert isinstance(events[1], SetTriggerable1DPositionsEvent) or isinstance(events[1], SetTriggerablePropertySequencesEvent)
assert isinstance(events[2], StartCapture)
assert events[2].number == 24 # 3 time points * 4 z-positions * 2 channels
assert events[2].num_blocks == 24 # 3 time points * 4 z-positions * 2 channels


expected_z_sequence = np.array([0, 0, 2, 2, 4, 4, 6, 6, 0, 0, 2, 2, 4, 4, 6, 6, 0, 0, 2, 2, 4, 4, 6, 6])
Expand Down Expand Up @@ -257,7 +257,7 @@ def test_sequenced_channels_and_positions():
assert isinstance(events[0], SetTriggerablePropertySequencesEvent) # Channel
assert isinstance(events[1], StartCapture)
assert isinstance(events[2], ReadoutData)
assert events[1].number == 6 # 2 channels * 3 positions
assert events[1].num_blocks == 6 # 2 channels * 3 positions

expected_channel_sequence = ['DAPI', 'FITC'] * 3 # Repeats for each position
assert events[0].property_sequences[0][2] == expected_channel_sequence
Expand Down

0 comments on commit b7b9b21

Please sign in to comment.