Skip to content

Commit

Permalink
feat: add reset_event_timer (#188)
Browse files Browse the repository at this point in the history
  • Loading branch information
tlambert03 authored Sep 25, 2024
1 parent fe35207 commit 2c3addb
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 5 deletions.
9 changes: 9 additions & 0 deletions src/useq/_iter_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class MDAEventDict(TypedDict, total=False):
sequence: MDASequence | None
# properties: list[tuple] | None
metadata: dict
reset_event_timer: bool


class PositionDict(TypedDict, total=False):
Expand Down Expand Up @@ -106,6 +107,7 @@ def _iter_sequence(
base_event_kwargs: MDAEventDict | None = None,
event_kwarg_overrides: MDAEventDict | None = None,
position_offsets: PositionDict | None = None,
_last_t_idx: int = -1,
) -> Iterator[MDAEvent]:
"""Helper function for `iter_sequence`.
Expand All @@ -132,6 +134,9 @@ def _iter_sequence(
A dictionary of offsets to apply to each position. This can be used to shift
all positions in a sub-sequence. Keys must be one of `x_pos`, `y_pos`, or
`z_pos` and values should be floats.s
_last_t_idx : int
The index of the last timepoint. This is used to determine if the event
should reset the event timer.
Yields
------
Expand Down Expand Up @@ -209,6 +214,7 @@ def _iter_sequence(
base_event_kwargs=event_kwargs.copy(),
event_kwarg_overrides=pos_overrides,
position_offsets=_offsets,
_last_t_idx=_last_t_idx,
)
continue
# note that position.sequence may be Falsey even if not None, for example
Expand All @@ -217,12 +223,15 @@ def _iter_sequence(
elif position.sequence is not None and position.sequence.autofocus_plan:
autofocus_plan = position.sequence.autofocus_plan

if event_kwargs["index"].get(Axis.TIME) == 0 and _last_t_idx != 0:
event_kwargs["reset_event_timer"] = True
event = MDAEvent.model_construct(**event_kwargs)
if autofocus_plan:
af_event = autofocus_plan.event(event)
if af_event:
yield af_event
yield event
_last_t_idx = event.index.get(Axis.TIME, _last_t_idx)


# ###################### Helper functions ######################
Expand Down
12 changes: 9 additions & 3 deletions src/useq/_mda_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ class MDAEvent(UseqModel):
time. By default, `None`.
min_start_time : float | None
Minimum start time of this event, in seconds. If provided, the engine will
pause until this time has elapsed (relative to the start of the sequence)
before starting this event. By default, `None`.
pause until this time has elapsed before starting this event. Times are
relative to the start of the sequence, or the last event with
`reset_event_timer` set to `True`.
pos_name : str | None
The name assigned to the position. By default, `None`.
x_pos : float | None
Expand Down Expand Up @@ -125,11 +126,15 @@ class MDAEvent(UseqModel):
Example of another action is [`useq.HardwareAutofocus`][] which could be used
to perform a hardware autofocus.
keep_shutter_open : bool
If True, the illumination shutter should be left open after the event has
If `True`, the illumination shutter should be left open after the event has
been executed, otherwise it should be closed. By default, `False`."
This is useful when the sequence of events being executed use the same
illumination scheme (such as a z-stack in a single channel), and closing and
opening the shutter between events would be slow.
reset_event_timer : bool
If `True`, the engine should reset the event timer to the time of this event,
and future `min_start_time` values will be relative to this event. By default,
`False`.
"""

# MappingProxyType is not subscriptable on Python 3.8
Expand All @@ -146,6 +151,7 @@ class MDAEvent(UseqModel):
metadata: Dict[str, Any] = Field(default_factory=dict)
action: AnyAction = Field(default_factory=AcquireImage)
keep_shutter_open: bool = False
reset_event_timer: bool = False

@field_validator("channel", mode="before")
def _validate_channel(cls, val: Any) -> Any:
Expand Down
18 changes: 16 additions & 2 deletions tests/test_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,12 +413,26 @@ def test_keep_shutter_open() -> None:
assert event.keep_shutter_open != (event.index["g"] == 3)


def test_z_plan_num_position():
def test_z_plan_num_position() -> None:
for i in range(1, 100):
plan = ZRangeAround(range=(i - 1) / 10, step=0.1)
assert plan.num_positions() == i
assert len(list(plan)) == i


def test_channel_str():
def test_channel_str() -> None:
assert MDAEvent(channel="DAPI") == MDAEvent(channel={"config": "DAPI"})


def test_reset_event_timer() -> None:
events = list(
MDASequence(
stage_positions=[(100, 100), (0, 0)],
time_plan={"interval": 1, "loops": 2},
axis_order="ptgcz",
)
)
assert events[0].reset_event_timer
assert not events[1].reset_event_timer
assert events[2].reset_event_timer
assert not events[3].reset_event_timer

0 comments on commit 2c3addb

Please sign in to comment.