Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- `HamiltonTCPClient.setup()` now resets all per-session state (client id, sequence numbers, instrument addresses, object registry) rather than carrying it into the new session, and refuses to run on an already-connected client instead of leaking the socket (#1195).
- `HamiltonTCPClient` no longer recurses without bound when a device fails the introspection queries that error enrichment itself issues. Enrichment is now non-re-entrant and falls back to the static HC_RESULT tables, so a degraded instrument yields a terse error instead of a `RecursionError` (#1195).
- `HamiltonTCPClient` no longer fails every command after the device sends a HARP control frame. MLPrep firmware sends one (options, no HOI body) shortly after registration; it was parsed as a command response and killed the reader. Frames with no routable message are skipped, as are unparsable frames, which is safe because frames are length-prefixed and consumed whole (#1195).
- `PlateAdapter.compute_plate_location` reads the grid from the plate's wells alone, so a plate carrying a lid can be assigned or moved onto a plate adapter instead of raising `ValueError: well spacing has to be uniform`.

### Changed

Expand Down
10 changes: 6 additions & 4 deletions pylabrobot/resources/plate_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,11 @@ def compute_plate_location(self, resource: Plate) -> Coordinate:
align the `Plate` well-grid with the adapter's hole grid."""

# Calculate Plate information (which is not directly accessible from the Plate class)
# Wells only: a plate's lid is among its children too.
# Child locations are never None, so we can safely ignore the type error
x_locations = sorted(set(well_n.location.x for well_n in resource.children)) # type: ignore
y_locations = sorted(set(well_n.location.y for well_n in resource.children)) # type: ignore
wells = resource.get_wells()
x_locations = sorted(set(well_n.location.x for well_n in wells)) # type: ignore
y_locations = sorted(set(well_n.location.y for well_n in wells)) # type: ignore

def calculate_well_spacing(float_list: List[float]):
"""Calculate the difference between every x and x+1 element in the list of floats."""
Expand All @@ -142,8 +144,8 @@ def calculate_well_spacing(float_list: List[float]):
plate_dx, plate_dy = float(x_locations[0]), float(y_locations[0])
plate_item_dx = abs(calculate_well_spacing(x_locations))
plate_item_dy = abs(calculate_well_spacing(y_locations))
well_size_x = resource.children[0].get_absolute_size_x()
well_size_y = resource.children[0].get_absolute_size_y()
well_size_x = wells[0].get_absolute_size_x()
well_size_y = wells[0].get_absolute_size_y()
# true_dz = resource.get_size_z() - resource.children[0].get_size_z()

# Well-grid to hole-grid compatibility check
Expand Down
31 changes: 31 additions & 0 deletions pylabrobot/resources/plate_adapter_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from pylabrobot.resources import (
Coordinate,
Lid,
Plate,
PlateAdapter,
Well,
Expand Down Expand Up @@ -94,3 +95,33 @@ def test_rectangular_hole_centers_each_axis_on_its_own_size(self):
well_center = plate.get_well("H1").get_location_wrt(adapter, x="c", y="c", z="b")
self.assertAlmostEqual(well_center.x, adapter.dx + adapter.adapter_hole_size_x / 2)
self.assertAlmostEqual(well_center.y, adapter.dy + adapter.adapter_hole_size_y / 2)

def test_lid_is_not_taken_for_a_well(self):
"""A plate is placed on the adapter where it goes without its lid."""

plate = Plate(
name="plate",
size_x=127.76,
size_y=85.48,
size_z=14.0,
ordered_items=create_ordered_items_2d(
Well,
num_items_x=12,
num_items_y=8,
dx=9.5,
dy=6.5,
dz=1.0,
item_dx=9.0,
item_dy=9.0,
size_x=6.0,
size_y=6.0,
size_z=10.0,
),
)
without_lid = _adapter.compute_plate_location(plate)

plate.assign_child_resource(
Lid(name="lid", size_x=127.76, size_y=85.48, size_z=8.0, nesting_z_height=6.0)
)

self.assertEqual(_adapter.compute_plate_location(plate), without_lid)
Loading