Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api): implement the liquid transfer function #17179

Open
wants to merge 9 commits into
base: AUTH-866-add-transfer-flow-builder-2
Choose a base branch
from

Conversation

sanni-t
Copy link
Member

@sanni-t sanni-t commented Jan 2, 2025

Closes AUTH-866

Overview

Final PR of the 3-PR series.
Implements InstrumentCore.transfer_liquid().

The transfer_liquid() method does the following:

  1. Loads the relevant liquid class record into protocol engine, gets the liquid class ID back. This will be used in command annotations in the future
  2. Breaks down the total transfer volume into piecewise transfers, if necessary.
  3. Does auto-tip handling, unless the user has specified to 'never' use a new tip.
  4. Calls aspirate_liquid_class() and dispense_liquid_class() for every source-> destination transfer.

This PR also updates the tiprack 'names' to URIs in the liquid class definition in shared data for 'water' only. We will have a separate PR for updating rest of the definitions.

Test Plan and Hands on Testing

  • Added some unit tests for things that are unit-testable
  • Added integration tests for verifying that transfer_liquid() execution succeeds for various supported configurations
  • TODO: on-robot testing

Additionally, we will be adding analysis snapshot tests with protocols that use various configurations for transferring with liquid classes.

Review requests

  • The implementation of transfer_liquid() turned out to be not easily unit-testable, mainly owing to the location of implementation (inside InstrumentCore). I plan on moving this function out of the InstrumentCore so that it can be unit-tested without the constraints of rest of the Instrument core. But this still serves as a robust implementation for doing end-to-end, integration testing so that's what I am focusing on in this PR.
  • This PR also makes liquid-classes-based transfer available for hardware testing and verification.

Risk assessment

Low. Doesn't change existing API

@sanni-t sanni-t changed the base branch from edge to AUTH-866-add-transfer-flow-builder-2 January 2, 2025 16:14
@sanni-t sanni-t marked this pull request as ready for review January 7, 2025 14:43
@sanni-t sanni-t requested review from a team as code owners January 7, 2025 14:43
@sanni-t sanni-t requested review from jbleon95 and ddcc4 and removed request for a team January 7, 2025 14:52
pip_api_name
for pip_api_name, pip_name in PIPETTE_API_NAMES_MAP.items()
if pip_name == pipette.pipetteName
][0]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nitpick: This can be more efficiently implemented as:

load_name = next(
  (pip_api_name
   for pip_api_name, pip_name in PIPETTE_API_NAMES_MAP.items()
   if pip_name == pipette.pipetteName),
  None
)
assert load_name
return load_name

@@ -883,7 +904,7 @@ def load_liquid_class(

liquid_class_record = LiquidClassRecord(
liquidClassName=liquid_class.name,
pipetteModel=self.get_model(), # TODO: verify this is the correct 'model' to use
pipetteModel=pipette_load_name, # TODO: verify this is the correct 'model' to use
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does comment still apply?

pipette_load_name=self.get_pipette_name(), # TODO: update this to use load name instead
tiprack_uri=tiprack_uri,
pipette_load_name=self.get_pipette_load_name(),
tiprack_uri=tiprack_uri_for_transfer_props,
)
transfer_props = liquid_class.get_for(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.load_liquid_class() above also calls liquid_class.get_for(), right?

Can you refactor self.load_liquid_class() to just take in the transfer_props directly as an argument?

@@ -1034,7 +1153,9 @@ def aspirate_liquid_class(
)
components_executor.aspirate_and_wait(volume=volume)
components_executor.retract_after_aspiration(volume=volume)
return components_executor.tip_state.last_liquid_and_air_gap_in_tip
last_contents = components_executor.tip_state.last_liquid_and_air_gap_in_tip
tip_contents[-1] = last_contents
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I'm a little confused what this is trying to do: it sometimes modifies the list that's passed in, and it sometimes modifies a list that was created local to this function?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants