Skip to content

Commit bb5b5cd

Browse files
authored
feat(api): add new InstrumentContext.consolidate_liquid() method (#17359)
Adds consolidate_liquid method to instrument context
1 parent 9ffb69c commit bb5b5cd

File tree

6 files changed

+405
-0
lines changed

6 files changed

+405
-0
lines changed

api/src/opentrons/protocol_api/core/engine/instrument.py

+12
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,18 @@ def distribute_liquid(
11101110
) -> None:
11111111
pass
11121112

1113+
def consolidate_liquid(
1114+
self,
1115+
liquid_class: LiquidClass,
1116+
volume: float,
1117+
source: List[Tuple[Location, WellCore]],
1118+
dest: Tuple[Location, WellCore],
1119+
new_tip: TransferTipPolicyV2,
1120+
tip_racks: List[Tuple[Location, LabwareCore]],
1121+
trash_location: Union[Location, TrashBin, WasteChute],
1122+
) -> None:
1123+
pass
1124+
11131125
def _get_location_and_well_core_from_next_tip_info(
11141126
self,
11151127
tip_info: NextTipInfo,

api/src/opentrons/protocol_api/core/instrument.py

+17
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,23 @@ def distribute_liquid(
343343
"""
344344
...
345345

346+
@abstractmethod
347+
def consolidate_liquid(
348+
self,
349+
liquid_class: LiquidClass,
350+
volume: float,
351+
source: List[Tuple[types.Location, WellCoreType]],
352+
dest: Tuple[types.Location, WellCoreType],
353+
new_tip: TransferTipPolicyV2,
354+
tip_racks: List[Tuple[types.Location, LabwareCoreType]],
355+
trash_location: Union[types.Location, TrashBin, WasteChute],
356+
) -> None:
357+
"""
358+
Consolidate liquid from multiple sources to a single destination
359+
using the specified liquid class properties.
360+
"""
361+
...
362+
346363
@abstractmethod
347364
def is_tip_tracking_available(self) -> bool:
348365
"""Return whether auto tip tracking is available for the pipette's current nozzle configuration."""

api/src/opentrons/protocol_api/core/legacy/legacy_instrument_core.py

+13
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,19 @@ def distribute_liquid(
586586
"""This will never be called because it was added in API 2.23"""
587587
assert False, "distribute_liquid is not supported in legacy context"
588588

589+
def consolidate_liquid(
590+
self,
591+
liquid_class: LiquidClass,
592+
volume: float,
593+
source: List[Tuple[types.Location, LegacyWellCore]],
594+
dest: Tuple[types.Location, LegacyWellCore],
595+
new_tip: TransferTipPolicyV2,
596+
tip_racks: List[Tuple[types.Location, LegacyLabwareCore]],
597+
trash_location: Union[types.Location, TrashBin, WasteChute],
598+
) -> None:
599+
"""This will never be called because it was added in API 2.23."""
600+
assert False, "consolidate_liquid is not supported in legacy context"
601+
589602
def get_active_channels(self) -> int:
590603
"""This will never be called because it was added in API 2.16."""
591604
assert False, "get_active_channels only supported in API 2.16 & later"

api/src/opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py

+13
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,19 @@ def distribute_liquid(
506506
"""This will never be called because it was added in API 2.23."""
507507
assert False, "distribute_liquid is not supported in legacy context"
508508

509+
def consolidate_liquid(
510+
self,
511+
liquid_class: LiquidClass,
512+
volume: float,
513+
source: List[Tuple[types.Location, LegacyWellCore]],
514+
dest: Tuple[types.Location, LegacyWellCore],
515+
new_tip: TransferTipPolicyV2,
516+
tip_racks: List[Tuple[types.Location, LegacyLabwareCore]],
517+
trash_location: Union[types.Location, TrashBin, WasteChute],
518+
) -> None:
519+
"""This will never be called because it was added in API 2.23."""
520+
assert False, "consolidate_liquid is not supported in legacy context"
521+
509522
def get_active_channels(self) -> int:
510523
"""This will never be called because it was added in API 2.16."""
511524
assert False, "get_active_channels only supported in API 2.16 & later"

api/src/opentrons/protocol_api/instrument_context.py

+88
Original file line numberDiff line numberDiff line change
@@ -1689,6 +1689,94 @@ def distribute_liquid(
16891689
)
16901690
return self
16911691

1692+
def consolidate_liquid(
1693+
self,
1694+
liquid_class: LiquidClass,
1695+
volume: float,
1696+
source: Union[
1697+
labware.Well, Sequence[labware.Well], Sequence[Sequence[labware.Well]]
1698+
],
1699+
dest: labware.Well,
1700+
new_tip: TransferTipPolicyV2Type = "once",
1701+
trash_location: Optional[
1702+
Union[types.Location, labware.Well, TrashBin, WasteChute]
1703+
] = None,
1704+
) -> InstrumentContext:
1705+
"""
1706+
Consolidate liquid from multiple sources to a single destination
1707+
using the specified liquid class properties.
1708+
1709+
TODO: Add args description.
1710+
"""
1711+
if not feature_flags.allow_liquid_classes(
1712+
robot_type=RobotTypeEnum.robot_literal_to_enum(
1713+
self._protocol_core.robot_type
1714+
)
1715+
):
1716+
raise NotImplementedError("This method is not implemented.")
1717+
if not isinstance(dest, labware.Well):
1718+
raise ValueError(
1719+
f"Destination should be a single Well but received {dest}."
1720+
)
1721+
flat_sources_list = validation.ensure_valid_flat_wells_list_for_transfer_v2(
1722+
source
1723+
)
1724+
for well in flat_sources_list + [dest]:
1725+
instrument.validate_takes_liquid(
1726+
location=well.top(),
1727+
reject_module=True,
1728+
reject_adapter=True,
1729+
)
1730+
1731+
valid_new_tip = validation.ensure_new_tip_policy(new_tip)
1732+
if valid_new_tip == TransferTipPolicyV2.NEVER:
1733+
if self._last_tip_picked_up_from is None:
1734+
raise RuntimeError(
1735+
"Pipette has no tip attached to perform transfer."
1736+
" Either do a pick_up_tip beforehand or specify a new_tip parameter"
1737+
" of 'once' or 'always'."
1738+
)
1739+
else:
1740+
tip_racks = [self._last_tip_picked_up_from.parent]
1741+
else:
1742+
tip_racks = self._tip_racks
1743+
if self.current_volume != 0:
1744+
raise RuntimeError(
1745+
"A transfer on a liquid class cannot start with liquid already in the tip."
1746+
" Ensure that all previously aspirated liquid is dispensed before starting"
1747+
" a new transfer."
1748+
)
1749+
1750+
_trash_location: Union[types.Location, labware.Well, TrashBin, WasteChute]
1751+
if trash_location is None:
1752+
saved_trash = self.trash_container
1753+
if isinstance(saved_trash, labware.Labware):
1754+
_trash_location = saved_trash.wells()[0]
1755+
else:
1756+
_trash_location = saved_trash
1757+
else:
1758+
_trash_location = trash_location
1759+
1760+
checked_trash_location = validation.ensure_valid_trash_location_for_transfer_v2(
1761+
trash_location=_trash_location
1762+
)
1763+
self._core.consolidate_liquid(
1764+
liquid_class=liquid_class,
1765+
volume=volume,
1766+
source=[
1767+
(types.Location(types.Point(), labware=well), well._core)
1768+
for well in flat_sources_list
1769+
],
1770+
dest=(types.Location(types.Point(), labware=dest), dest._core),
1771+
new_tip=valid_new_tip,
1772+
tip_racks=[
1773+
(types.Location(types.Point(), labware=rack), rack._core)
1774+
for rack in tip_racks
1775+
],
1776+
trash_location=checked_trash_location,
1777+
)
1778+
return self
1779+
16921780
@requires_version(2, 0)
16931781
def delay(self, *args: Any, **kwargs: Any) -> None:
16941782
"""

0 commit comments

Comments
 (0)