Skip to content

Commit

Permalink
feat(shared-data): add custom & default thermocycler overlap offsets …
Browse files Browse the repository at this point in the history
…for labware (#13630) (#13750)

* added TC overlaps for nest & biorad pcr plates
* added a backwards-compatible default overlap for TC labware on OT2
* fix pd e2e migration fixture
---------

Co-authored-by: Sanniti Pimpley <[email protected]>
  • Loading branch information
jerader and sanni-t authored Oct 10, 2023
1 parent 1f3cb50 commit 6c24a34
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 12 deletions.
17 changes: 16 additions & 1 deletion api/src/opentrons/protocol_engine/state/labware.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,12 +560,27 @@ def get_module_overlap_offsets(
"""Get the labware's overlap with requested module model."""
definition = self.get_definition(labware_id)
stacking_overlap = definition.stackingOffsetWithModule.get(
str(module_model.value), OverlapOffset(x=0, y=0, z=0)
str(module_model.value)
)
if not stacking_overlap:
if self._is_thermocycler_on_ot2(module_model):
return OverlapOffset(x=0, y=0, z=10.7)
else:
return OverlapOffset(x=0, y=0, z=0)

return OverlapOffset(
x=stacking_overlap.x, y=stacking_overlap.y, z=stacking_overlap.z
)

def _is_thermocycler_on_ot2(self, module_model: ModuleModel) -> bool:
"""Whether the given module is a thermocycler with the current deck being an OT2 deck."""
robot_model = self.get_deck_definition()["robot"]["model"]
return (
module_model
in [ModuleModel.THERMOCYCLER_MODULE_V1, ModuleModel.THERMOCYCLER_MODULE_V2]
and robot_model == "OT-2 Standard"
)

def get_default_magnet_height(self, module_id: str, offset: float) -> float:
"""Return a labware's default Magnetic Module engage height with added offset, if supplied.
Expand Down
92 changes: 81 additions & 11 deletions api/tests/opentrons/protocol_engine/state/test_labware_view.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Labware state store tests."""
import pytest
from datetime import datetime
from typing import Dict, Optional, cast, ContextManager, Any, Union
from typing import Dict, Optional, cast, ContextManager, Any, Union, NamedTuple, List
from contextlib import nullcontext as does_not_raise

from opentrons_shared_data.deck import load as load_deck
from opentrons_shared_data.deck.dev_types import DeckDefinitionV3
from opentrons_shared_data.pipette.dev_types import LabwareUri
from opentrons_shared_data.labware.labware_definition import (
Expand All @@ -13,6 +14,11 @@
GripperOffsets,
OffsetVector,
)

from opentrons.protocols.api_support.deck_type import (
STANDARD_OT2_DECK,
STANDARD_OT3_DECK,
)
from opentrons.protocols.models import LabwareDefinition
from opentrons.types import DeckSlotName, Point, MountType

Expand All @@ -39,7 +45,6 @@
LabwareLoadParams,
)


plate = LoadedLabware(
id="plate-id",
loadName="plate-load-name",
Expand Down Expand Up @@ -686,26 +691,91 @@ def test_get_labware_overlap_offsets() -> None:
assert result == OverlapOffset(x=1, y=2, z=3)


def test_get_module_overlap_offsets() -> None:
class ModuleOverlapSpec(NamedTuple):
"""Spec data to test LabwareView.get_module_overlap_offsets."""

spec_deck_definition: DeckDefinitionV3
module_model: ModuleModel
stacking_offset_with_module: Dict[str, SharedDataOverlapOffset]
expected_offset: OverlapOffset


module_overlap_specs: List[ModuleOverlapSpec] = [
ModuleOverlapSpec(
# Labware on temp module on OT2, with stacking overlap for temp module
spec_deck_definition=load_deck(STANDARD_OT2_DECK, 3),
module_model=ModuleModel.TEMPERATURE_MODULE_V2,
stacking_offset_with_module={
str(ModuleModel.TEMPERATURE_MODULE_V2.value): SharedDataOverlapOffset(
x=1, y=2, z=3
),
},
expected_offset=OverlapOffset(x=1, y=2, z=3),
),
ModuleOverlapSpec(
# Labware on TC Gen1 on OT2, with stacking overlap for TC Gen1
spec_deck_definition=load_deck(STANDARD_OT2_DECK, 3),
module_model=ModuleModel.THERMOCYCLER_MODULE_V1,
stacking_offset_with_module={
str(ModuleModel.THERMOCYCLER_MODULE_V1.value): SharedDataOverlapOffset(
x=11, y=22, z=33
),
},
expected_offset=OverlapOffset(x=11, y=22, z=33),
),
ModuleOverlapSpec(
# Labware on TC Gen2 on OT2, with no stacking overlap
spec_deck_definition=load_deck(STANDARD_OT2_DECK, 3),
module_model=ModuleModel.THERMOCYCLER_MODULE_V2,
stacking_offset_with_module={},
expected_offset=OverlapOffset(x=0, y=0, z=10.7),
),
ModuleOverlapSpec(
# Labware on TC Gen2 on Flex, with no stacking overlap
spec_deck_definition=load_deck(STANDARD_OT3_DECK, 3),
module_model=ModuleModel.THERMOCYCLER_MODULE_V2,
stacking_offset_with_module={},
expected_offset=OverlapOffset(x=0, y=0, z=0),
),
ModuleOverlapSpec(
# Labware on TC Gen2 on Flex, with stacking overlap for TC Gen2
spec_deck_definition=load_deck(STANDARD_OT3_DECK, 3),
module_model=ModuleModel.THERMOCYCLER_MODULE_V2,
stacking_offset_with_module={
str(ModuleModel.THERMOCYCLER_MODULE_V2.value): SharedDataOverlapOffset(
x=111, y=222, z=333
),
},
expected_offset=OverlapOffset(x=111, y=222, z=333),
),
]


@pytest.mark.parametrize(
argnames=ModuleOverlapSpec._fields,
argvalues=module_overlap_specs,
)
def test_get_module_overlap_offsets(
spec_deck_definition: DeckDefinitionV3,
module_model: ModuleModel,
stacking_offset_with_module: Dict[str, SharedDataOverlapOffset],
expected_offset: OverlapOffset,
) -> None:
"""It should get the labware overlap offsets."""
subject = get_labware_view(
deck_definition=spec_deck_definition,
labware_by_id={"plate-id": plate},
definitions_by_uri={
"some-plate-uri": LabwareDefinition.construct( # type: ignore[call-arg]
stackingOffsetWithModule={
str(
ModuleModel.TEMPERATURE_MODULE_V2.value
): SharedDataOverlapOffset(x=1, y=2, z=3)
}
stackingOffsetWithModule=stacking_offset_with_module
)
},
)

result = subject.get_module_overlap_offsets(
labware_id="plate-id", module_model=ModuleModel.TEMPERATURE_MODULE_V2
labware_id="plate-id", module_model=module_model
)

assert result == OverlapOffset(x=1, y=2, z=3)
assert result == expected_offset


def test_get_default_magnet_height(
Expand Down
7 changes: 7 additions & 0 deletions protocol-designer/fixtures/protocol/7/doItAllV7.json
Original file line number Diff line number Diff line change
Expand Up @@ -2415,6 +2415,13 @@
"stackingOffsetWithLabware": {
"opentrons_96_pcr_adapter": { "x": 0, "y": 0, "z": 10.2 },
"opentrons_96_well_aluminum_block": { "x": 0, "y": 0, "z": 12.66 }
},
"stackingOffsetWithModule": {
"thermocyclerModuleV2": {
"x": 0,
"y": 0,
"z": 10.8
}
}
},
"opentrons/opentrons_24_aluminumblock_nest_1.5ml_snapcap/1": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1025,5 +1025,12 @@
"y": 0,
"z": 15.41
}
},
"stackingOffsetWithModule": {
"thermocyclerModuleV2": {
"x": 0,
"y": 0,
"z": 10.75
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1028,5 +1028,12 @@
"y": 0,
"z": 12.66
}
},
"stackingOffsetWithModule": {
"thermocyclerModuleV2": {
"x": 0,
"y": 0,
"z": 10.8
}
}
}

0 comments on commit 6c24a34

Please sign in to comment.