Skip to content

Commit

Permalink
updated validate_well_position and command schema 10
Browse files Browse the repository at this point in the history
  • Loading branch information
pmoegenburg committed Oct 10, 2024
1 parent 67d53a4 commit 053a47c
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 19 deletions.
18 changes: 15 additions & 3 deletions api/src/opentrons/protocol_engine/state/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,14 +430,25 @@ def get_labware_position(self, labware_id: str) -> Point:
def validate_well_position(
self,
well_location: WellLocations,
well_depth: float,
z_offset: float,
pipette_id: Optional[str] = None,
) -> None:
"""Raise exception if operation location is not within well.
Primarily this checks if there is not enough liquid in a well to do meniscus-relative static aspiration.
"""
if z_offset < 0:
invalid = False
if well_location.origin == WellOrigin.MENISCUS:
assert pipette_id is not None
lld_min_height = self._pipettes.get_current_tip_lld_settings(
pipette_id=pipette_id
)
if z_offset < lld_min_height:
invalid = True
elif z_offset < 0:
invalid = True

if invalid:
if isinstance(well_location, PickUpTipWellLocation):
raise OperationLocationNotInWellError(
f"Specifying {well_location.origin} with an offset of {well_location.offset} results in an operation location below the bottom of the well"
Expand All @@ -453,6 +464,7 @@ def get_well_position(
well_name: str,
well_location: Optional[WellLocations] = None,
operation_volume: Optional[float] = None,
pipette_id: Optional[str] = None,
) -> Point:
"""Given relative well location in a labware, get absolute position."""
labware_pos = self.get_labware_position(labware_id)
Expand All @@ -471,7 +483,7 @@ def get_well_position(
)
offset = offset.copy(update={"z": offset.z + offset_adjustment})
self.validate_well_position(
well_location=well_location, well_depth=well_depth, z_offset=offset.z
well_location=well_location, z_offset=offset.z, pipette_id=pipette_id
)

return Point(
Expand Down
1 change: 1 addition & 0 deletions api/src/opentrons/protocol_engine/state/motion.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ def get_movement_waypoints_to_well(
well_name=well_name,
well_location=well_location,
operation_volume=operation_volume,
pipette_id=pipette_id,
)

move_type = _move_types.get_move_type_to_well(
Expand Down
20 changes: 20 additions & 0 deletions api/tests/opentrons/protocol_engine/state/test_geometry_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -1511,6 +1511,7 @@ def test_get_well_position_with_meniscus_offset(
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."""
Expand Down Expand Up @@ -1541,6 +1542,9 @@ def test_get_well_position_with_meniscus_offset(
decoy.when(
mock_well_view.get_last_measured_liquid_height("labware-id", "B2")
).then_return(70.5)
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",
Expand All @@ -1549,6 +1553,7 @@ def test_get_well_position_with_meniscus_offset(
origin=WellOrigin.MENISCUS,
offset=WellOffset(x=2, y=3, z=4),
),
pipette_id="pipette-id",
)

assert result == Point(
Expand All @@ -1564,6 +1569,7 @@ def test_get_well_position_with_meniscus_and_literal_volume_offset(
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 with a volume offset."""
Expand Down Expand Up @@ -1600,6 +1606,9 @@ def test_get_well_position_with_meniscus_and_literal_volume_offset(
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",
Expand All @@ -1610,6 +1619,7 @@ def test_get_well_position_with_meniscus_and_literal_volume_offset(
volumeOffset="operationVolume",
),
operation_volume=-1245.833,
pipette_id="pipette-id",
)

assert result == Point(
Expand All @@ -1625,6 +1635,7 @@ def test_get_well_position_with_meniscus_and_float_volume_offset(
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 with a volume offset."""
Expand Down Expand Up @@ -1661,6 +1672,9 @@ def test_get_well_position_with_meniscus_and_float_volume_offset(
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",
Expand All @@ -1670,6 +1684,7 @@ def test_get_well_position_with_meniscus_and_float_volume_offset(
offset=WellOffset(x=2, y=3, z=4),
volumeOffset=-1245.833,
),
pipette_id="pipette-id",
)

assert result == Point(
Expand All @@ -1685,6 +1700,7 @@ def test_get_well_position_raises_validation_error(
mock_labware_view: LabwareView,
mock_well_view: WellView,
mock_addressable_area_view: AddressableAreaView,
mock_pipette_view: PipetteView,
subject: GeometryView,
) -> None:
"""It should raise a validation error when a volume offset is too large (ie location is below the well bottom)."""
Expand Down Expand Up @@ -1721,6 +1737,9 @@ def test_get_well_position_raises_validation_error(
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)

with pytest.raises(errors.OperationLocationNotInWellError):
subject.get_well_position(
Expand All @@ -1732,6 +1751,7 @@ def test_get_well_position_raises_validation_error(
volumeOffset="operationVolume",
),
operation_volume=-100.0,
pipette_id="pipette-id",
)


Expand Down
9 changes: 7 additions & 2 deletions api/tests/opentrons/protocol_engine/state/test_motion_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,9 @@ def test_get_movement_waypoints_to_well_for_y_center(
).then_return(False)

decoy.when(
geometry_view.get_well_position("labware-id", "well-name", WellLocation(), None)
geometry_view.get_well_position(
"labware-id", "well-name", WellLocation(), None, "pipette-id"
)
).then_return(Point(x=4, y=5, z=6))

decoy.when(
Expand Down Expand Up @@ -391,7 +393,9 @@ def test_get_movement_waypoints_to_well_for_xy_center(
).then_return(True)

decoy.when(
geometry_view.get_well_position("labware-id", "well-name", WellLocation(), None)
geometry_view.get_well_position(
"labware-id", "well-name", WellLocation(), None, "pipette-id"
)
).then_return(Point(x=4, y=5, z=6))

decoy.when(
Expand Down Expand Up @@ -461,6 +465,7 @@ def test_get_movement_waypoints_to_well_raises(
well_name="A1",
well_location=None,
operation_volume=None,
pipette_id="pipette-id",
)
).then_return(Point(x=4, y=5, z=6))
decoy.when(pipette_view.get_current_location()).then_return(None)
Expand Down
84 changes: 70 additions & 14 deletions shared-data/command/schemas/10.json
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,9 @@
}
}
},
"WellLocation": {
"title": "WellLocation",
"description": "A relative location in reference to a well's location.",
"LiquidHandlingWellLocation": {
"title": "LiquidHandlingWellLocation",
"description": "A relative location in reference to a well's location.\n\nTo be used with commands that handle liquids.",
"type": "object",
"properties": {
"origin": {
Expand All @@ -341,6 +341,20 @@
},
"offset": {
"$ref": "#/definitions/WellOffset"
},
"volumeOffset": {
"title": "Volumeoffset",
"description": "A volume of liquid, in \u00b5L, to offset the z-axis offset. When \"operationVolume\" is specified, this volume is pulled from the volume command parameter.",
"default": 0.0,
"anyOf": [
{
"type": "number"
},
{
"enum": ["operationVolume"],
"type": "string"
}
]
}
}
},
Expand All @@ -364,7 +378,7 @@
"description": "Relative well location at which to perform the operation",
"allOf": [
{
"$ref": "#/definitions/WellLocation"
"$ref": "#/definitions/LiquidHandlingWellLocation"
}
]
},
Expand Down Expand Up @@ -800,7 +814,7 @@
"description": "Relative well location at which to perform the operation",
"allOf": [
{
"$ref": "#/definitions/WellLocation"
"$ref": "#/definitions/LiquidHandlingWellLocation"
}
]
},
Expand Down Expand Up @@ -939,7 +953,7 @@
"description": "Relative well location at which to perform the operation",
"allOf": [
{
"$ref": "#/definitions/WellLocation"
"$ref": "#/definitions/LiquidHandlingWellLocation"
}
]
},
Expand Down Expand Up @@ -2005,6 +2019,30 @@
},
"required": ["params"]
},
"WellLocation": {
"title": "WellLocation",
"description": "A relative location in reference to a well's location.",
"type": "object",
"properties": {
"origin": {
"default": "top",
"allOf": [
{
"$ref": "#/definitions/WellOrigin"
}
]
},
"offset": {
"$ref": "#/definitions/WellOffset"
},
"volumeOffset": {
"title": "Volumeoffset",
"description": "A volume of liquid, in \u00b5L, to offset the z-axis offset.",
"default": 0.0,
"type": "number"
}
}
},
"MoveToWellParams": {
"title": "MoveToWellParams",
"description": "Payload required to move a pipette to a specific well.",
Expand Down Expand Up @@ -2410,11 +2448,34 @@
},
"required": ["params"]
},
"PickUpTipWellLocation": {
"title": "PickUpTipWellLocation",
"description": "A relative location in reference to a well's location.\n\nTo be used for picking up tips.",
"type": "object",
"properties": {
"origin": {
"default": "top",
"allOf": [
{
"$ref": "#/definitions/WellOrigin"
}
]
},
"offset": {
"$ref": "#/definitions/WellOffset"
}
}
},
"PickUpTipParams": {
"title": "PickUpTipParams",
"description": "Payload needed to move a pipette to a specific well.",
"type": "object",
"properties": {
"pipetteId": {
"title": "Pipetteid",
"description": "Identifier of pipette to use for liquid handling.",
"type": "string"
},
"labwareId": {
"title": "Labwareid",
"description": "Identifier of labware to use.",
Expand All @@ -2427,20 +2488,15 @@
},
"wellLocation": {
"title": "Welllocation",
"description": "Relative well location at which to perform the operation",
"description": "Relative well location at which to pick up the tip.",
"allOf": [
{
"$ref": "#/definitions/WellLocation"
"$ref": "#/definitions/PickUpTipWellLocation"
}
]
},
"pipetteId": {
"title": "Pipetteid",
"description": "Identifier of pipette to use for liquid handling.",
"type": "string"
}
},
"required": ["labwareId", "wellName", "pipetteId"]
"required": ["pipetteId", "labwareId", "wellName"]
},
"PickUpTipCreate": {
"title": "PickUpTipCreate",
Expand Down

0 comments on commit 053a47c

Please sign in to comment.