Skip to content

Commit

Permalink
refactored getting liquid values, fixed and added tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pmoegenburg committed Oct 23, 2024
1 parent e2a6c3d commit a6e23b0
Show file tree
Hide file tree
Showing 5 changed files with 334 additions and 44 deletions.
25 changes: 12 additions & 13 deletions api/src/opentrons/protocol_engine/state/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -1402,26 +1402,25 @@ def get_meniscus_height(
) -> float:
"""Returns stored meniscus height in specified well."""
(
loaded_volume_info,
probed_height_info,
probed_volume_info,
) = self._wells.get_well_liquid_info(labware_id=labware_id, well_name=well_name)
if probed_height_info:
assert probed_height_info.height is not None
return probed_height_info.height
elif loaded_volume_info:
assert loaded_volume_info.volume is not None
loaded_volume,
probed_height,
probed_volume,
) = self._wells.get_well_liquid_values(
labware_id=labware_id, well_name=well_name
)
if probed_height:
return probed_height
elif loaded_volume:
return self.get_well_height_at_volume(
labware_id=labware_id,
well_name=well_name,
volume=loaded_volume_info.volume,
volume=loaded_volume,
)
elif probed_volume_info:
assert probed_volume_info.volume is not None
elif probed_volume:
return self.get_well_height_at_volume(
labware_id=labware_id,
well_name=well_name,
volume=probed_volume_info.volume,
volume=probed_volume,
)
else:
raise errors.LiquidHeightUnknownError(
Expand Down
18 changes: 7 additions & 11 deletions api/src/opentrons/protocol_engine/state/wells.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,11 @@ def has_measured_liquid_height(self, labware_id: str, well_name: str) -> bool:
except KeyError:
return False

def get_well_liquid_info(
def get_well_liquid_values(
self, labware_id: str, well_name: str
) -> Tuple[
Optional[LoadedVolumeInfo],
Optional[ProbedHeightInfo],
Optional[ProbedVolumeInfo],
]:
"""Return all the liquid info for a well."""
loaded_volume_info = self._state.loaded_volumes[labware_id][well_name]
probed_height_info = self._state.probed_heights[labware_id][well_name]
probed_volume_info = self._state.probed_volumes[labware_id][well_name]
return loaded_volume_info, probed_height_info, probed_volume_info
) -> Tuple[Optional[float], Optional[float], Optional[float]]:
"""Return all the liquid values for a well."""
loaded_volume = self._state.loaded_volumes[labware_id][well_name].volume
probed_height = self._state.probed_heights[labware_id][well_name].height
probed_volume = self._state.probed_volumes[labware_id][well_name].volume
return loaded_volume, probed_height, probed_volume
25 changes: 24 additions & 1 deletion api/tests/opentrons/protocol_engine/state/command_fixtures.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Command factories to use in tests as data fixtures."""
from datetime import datetime
from pydantic import BaseModel
from typing import Optional, cast
from typing import Optional, cast, Dict

from opentrons_shared_data.pipette.types import PipetteNameType
from opentrons.types import MountType
Expand Down Expand Up @@ -338,6 +338,29 @@ def create_liquid_probe_command(
)


def create_load_liquid_command(
liquid_id: str = "liquid-id",
labware_id: str = "labware-id",
volume_by_well: Dict[str, float] = {"A1": 30, "B2": 100},
) -> cmd.LoadLiquid:
"""Get a completed Load Liquid command."""
params = cmd.LoadLiquidParams(
liquidId=liquid_id,
labwareId=labware_id,
volumeByWell=volume_by_well,
)
result = cmd.LoadLiquidResult()

return cmd.LoadLiquid(
id="command-id",
key="command-key",
status=cmd.CommandStatus.SUCCEEDED,
createdAt=datetime.now(),
params=params,
result=result,
)


def create_pick_up_tip_command(
pipette_id: str,
labware_id: str = "labware-id",
Expand Down
94 changes: 79 additions & 15 deletions api/tests/opentrons/protocol_engine/state/test_geometry_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -1539,9 +1539,9 @@ def test_get_well_position_with_meniscus_offset(
decoy.when(mock_labware_view.get_well_definition("labware-id", "B2")).then_return(
well_def
)
decoy.when(
mock_well_view.get_last_measured_liquid_height("labware-id", "B2")
).then_return(70.5)
decoy.when(mock_well_view.get_well_liquid_values("labware-id", "B2")).then_return(
(None, 70.5, None)
)
decoy.when(
mock_pipette_view.get_current_tip_lld_settings(pipette_id="pipette-id")
).then_return(0.5)
Expand Down Expand Up @@ -1597,9 +1597,9 @@ def test_get_well_position_with_meniscus_and_literal_volume_offset(
decoy.when(mock_labware_view.get_well_definition("labware-id", "B2")).then_return(
well_def
)
decoy.when(
mock_well_view.get_last_measured_liquid_height("labware-id", "B2")
).then_return(45.0)
decoy.when(mock_well_view.get_well_liquid_values("labware-id", "B2")).then_return(
(None, 45.0, None)
)
labware_def = _load_labware_definition_data()
assert labware_def.innerLabwareGeometry is not None
inner_well_def = labware_def.innerLabwareGeometry["welldefinition1111"]
Expand Down Expand Up @@ -1663,9 +1663,9 @@ def test_get_well_position_with_meniscus_and_float_volume_offset(
decoy.when(mock_labware_view.get_well_definition("labware-id", "B2")).then_return(
well_def
)
decoy.when(
mock_well_view.get_last_measured_liquid_height("labware-id", "B2")
).then_return(45.0)
decoy.when(mock_well_view.get_well_liquid_values("labware-id", "B2")).then_return(
(None, 45.0, None)
)
labware_def = _load_labware_definition_data()
assert labware_def.innerLabwareGeometry is not None
inner_well_def = labware_def.innerLabwareGeometry["welldefinition1111"]
Expand Down Expand Up @@ -1728,9 +1728,9 @@ def test_get_well_position_raises_validation_error(
decoy.when(mock_labware_view.get_well_definition("labware-id", "B2")).then_return(
well_def
)
decoy.when(
mock_well_view.get_last_measured_liquid_height("labware-id", "B2")
).then_return(40.0)
decoy.when(mock_well_view.get_well_liquid_values("labware-id", "B2")).then_return(
(None, 40.0, None)
)
labware_def = _load_labware_definition_data()
assert labware_def.innerLabwareGeometry is not None
inner_well_def = labware_def.innerLabwareGeometry["welldefinition1111"]
Expand All @@ -1755,6 +1755,70 @@ def test_get_well_position_raises_validation_error(
)


def test_get_meniscus_height(
decoy: Decoy,
well_plate_def: LabwareDefinition,
mock_labware_view: LabwareView,
mock_well_view: WellView,
mock_addressable_area_view: AddressableAreaView,
mock_pipette_view: PipetteView,
subject: GeometryView,
) -> None:
"""It should be able to get the position of a well meniscus in a labware."""
labware_data = LoadedLabware(
id="labware-id",
loadName="load-name",
definitionUri="definition-uri",
location=DeckSlotLocation(slotName=DeckSlotName.SLOT_4),
offsetId="offset-id",
)
calibration_offset = LabwareOffsetVector(x=1, y=-2, z=3)
slot_pos = Point(4, 5, 6)
well_def = well_plate_def.wells["B2"]

decoy.when(mock_labware_view.get("labware-id")).then_return(labware_data)
decoy.when(mock_labware_view.get_definition("labware-id")).then_return(
well_plate_def
)
decoy.when(mock_labware_view.get_labware_offset_vector("labware-id")).then_return(
calibration_offset
)
decoy.when(
mock_addressable_area_view.get_addressable_area_position(DeckSlotName.SLOT_4.id)
).then_return(slot_pos)
decoy.when(mock_labware_view.get_well_definition("labware-id", "B2")).then_return(
well_def
)
decoy.when(mock_well_view.get_well_liquid_values("labware-id", "B2")).then_return(
(2000.0, None, None)
)
labware_def = _load_labware_definition_data()
assert labware_def.innerLabwareGeometry is not None
inner_well_def = labware_def.innerLabwareGeometry["welldefinition1111"]
decoy.when(mock_labware_view.get_well_geometry("labware-id", "B2")).then_return(
inner_well_def
)
decoy.when(
mock_pipette_view.get_current_tip_lld_settings(pipette_id="pipette-id")
).then_return(0.5)

result = subject.get_well_position(
labware_id="labware-id",
well_name="B2",
well_location=WellLocation(
origin=WellOrigin.MENISCUS,
offset=WellOffset(x=2, y=3, z=4),
),
pipette_id="pipette-id",
)

assert result == Point(
x=slot_pos[0] + 1 + well_def.x + 2,
y=slot_pos[1] - 2 + well_def.y + 3,
z=slot_pos[2] + 3 + well_def.z + 4 + 39.2423,
)


def test_get_relative_well_location(
decoy: Decoy,
well_plate_def: LabwareDefinition,
Expand Down Expand Up @@ -3133,9 +3197,9 @@ def test_validate_dispense_volume_into_well_meniscus(
decoy.when(mock_labware_view.get_well_geometry("labware-id", "A1")).then_return(
inner_well_def
)
decoy.when(
mock_well_view.get_last_measured_liquid_height("labware-id", "A1")
).then_return(40.0)
decoy.when(mock_well_view.get_well_liquid_values("labware-id", "A1")).then_return(
(None, 40.0, None)
)

with pytest.raises(errors.InvalidDispenseVolumeError):
subject.validate_dispense_volume_into_well(
Expand Down
Loading

0 comments on commit a6e23b0

Please sign in to comment.