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

bug: Inappropriate disposal or air_gap volume causes hang in transfers.py #6170

Closed
tanaes opened this issue Jul 17, 2020 · 3 comments
Closed
Assignees
Labels
api Affects the `api` project bug robot-svcs Falls under the purview of the Robot Services squad (formerly CPX, Core Platform Experience).

Comments

@tanaes
Copy link

tanaes commented Jul 17, 2020

Overview

Accidentally including an inappropriate disposal volume (disposal_volume=pipette_volume) causes a hang in transfers. This leads to infinite simulation times and difficulty troubleshooting.

It appears to be due to bad assumptions in this while statement in transfers.py:

while (sum(a[0] for a in asp_grouped) +
self._strategy.disposal_volume +
self._strategy.air_gap +
current_xfer[0]) <= self._max_volume:
asp_grouped.append(current_xfer)
current_xfer = next(plan_iter)

I'm not familiar with the code base, but it seems like you want to handle the case where the summed value exceeds self._max_volume.

Steps to reproduce

Minimal example protocol:

from opentrons import protocol_api

metadata = {'apiLevel': '2.5',
            'author': 'Jon Sanders'}

def run(protocol: protocol_api.ProtocolContext):

    protocol.home()

    tiprack_reagents = protocol.load_labware('opentrons_96_tiprack_20ul', 
                                             11)
    reagents = protocol.load_labware('opentrons_96_aluminumblock_generic_pcr_strip_200ul',
                                     1, 'reagents')
    samples = protocol.load_labware('biorad_96_wellplate_200ul_pcr',
                                   4, 'samples')

    pipette_right = protocol.load_instrument('p10_multi', 
                                            'right',
                                            tip_racks=[tiprack_reagents])


    pipette_right.distribute(10,
                         reagents['A1'],
                         samples.wells(),
                         disposal_volume=10,
                         new_tip='once')

Out from kernel interrupt:

---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
<ipython-input-8-b50bc670336c> in <module>
      1 protocol_file = open('../test.py', 'r')
      2 
----> 3 runlog, _bundle = simulate(protocol_file)
      4 
      5 protocol_file.close()

~/miniconda3/envs/py3/lib/python3.7/site-packages/opentrons/simulate.py in simulate(protocol_file, file_name, custom_labware_paths, custom_data_paths, propagate_logs, hardware_simulator_file_path, log_level)
    342         scraper = CommandScraper(stack_logger, log_level, context.broker)
    343         try:
--> 344             execute.run_protocol(protocol, context)
    345             if isinstance(protocol, PythonProtocol)\
    346                and protocol.api_level >= APIVersion(2, 0)\

~/miniconda3/envs/py3/lib/python3.7/site-packages/opentrons/protocol_api/execute.py in run_protocol(protocol, context)
    109     if isinstance(protocol, PythonProtocol):
    110         if protocol.api_level >= APIVersion(2, 0):
--> 111             _run_python(protocol, context)
    112         else:
    113             raise RuntimeError(

~/miniconda3/envs/py3/lib/python3.7/site-packages/opentrons/protocol_api/execute.py in _run_python(proto, context)
     86     new_globs['__context'] = context
     87     try:
---> 88         exec('run(__context)', new_globs)
     89     except (SmoothieAlarm, asyncio.CancelledError, ExecutionCancelledError):
     90         # this is a protocol cancel and shouldn't have special logging

<string> in <module>

<protocol> in run(protocol)

~/miniconda3/envs/py3/lib/python3.7/site-packages/opentrons/protocol_api/util.py in decorated(*args, **kwargs)
    612                 do_publish(
    613                     broker, command, f, 'before', None, meta, *args, **kwargs)
--> 614             res = f(*args, **kwargs)
    615             if after:
    616                 do_publish(

~/miniconda3/envs/py3/lib/python3.7/site-packages/opentrons/protocol_api/util.py in _check_version_wrapper(*args, **kwargs)
    368                     f'must increase your API version to {added_in} to '
    369                     'use this functionality.')
--> 370             return decorated_obj(*args, **kwargs)
    371 
    372         return _check_version_wrapper

~/miniconda3/envs/py3/lib/python3.7/site-packages/opentrons/protocol_api/instrument_context.py in distribute(self, volume, source, dest, *args, **kwargs)
    848             'disposal_volume', self.min_volume)
    849         kwargs['mix_after'] = (0, 0)
--> 850         return self.transfer(volume, source, dest, **kwargs)
    851 
    852     @cmds.publish.both(command=cmds.consolidate)

~/miniconda3/envs/py3/lib/python3.7/site-packages/opentrons/protocol_api/util.py in decorated(*args, **kwargs)
    612                 do_publish(
    613                     broker, command, f, 'before', None, meta, *args, **kwargs)
--> 614             res = f(*args, **kwargs)
    615             if after:
    616                 do_publish(

~/miniconda3/envs/py3/lib/python3.7/site-packages/opentrons/protocol_api/util.py in _check_version_wrapper(*args, **kwargs)
    368                     f'must increase your API version to {added_in} to '
    369                     'use this functionality.')
--> 370             return decorated_obj(*args, **kwargs)
    371 
    372         return _check_version_wrapper

~/miniconda3/envs/py3/lib/python3.7/site-packages/opentrons/protocol_api/instrument_context.py in transfer(self, volume, source, dest, trash, **kwargs)
   1025                                       self.api_version, kwargs['mode'],
   1026                                       transfer_options)
-> 1027         self._execute_transfer(plan)
   1028         return self
   1029 

~/miniconda3/envs/py3/lib/python3.7/site-packages/opentrons/protocol_api/instrument_context.py in _execute_transfer(self, plan)
   1029 
   1030     def _execute_transfer(self, plan: transfers.TransferPlan):
-> 1031         for cmd in plan:
   1032             getattr(self, cmd['method'])(*cmd['args'], **cmd['kwargs'])
   1033 

~/miniconda3/envs/py3/lib/python3.7/site-packages/opentrons/protocol_api/transfers.py in __iter__(self)
    426         yield from {TransferMode.CONSOLIDATE: self._plan_consolidate,
    427                     TransferMode.DISTRIBUTE: self._plan_distribute,
--> 428                     TransferMode.TRANSFER: self._plan_transfer}[self._mode]()
    429         if self._strategy.new_tip == types.TransferTipPolicy.ONCE:
    430             if self._strategy.drop_tip_strategy == DropTipStrategy.RETURN:

~/miniconda3/envs/py3/lib/python3.7/site-packages/opentrons/protocol_api/transfers.py in _plan_distribute(self)
    564                 while (sum(a[0] for a in asp_grouped) +
    565                        self._strategy.disposal_volume +
--> 566                        self._strategy.air_gap +
    567                        current_xfer[0]) <= self._max_volume:
    568                     asp_grouped.append(current_xfer)

~/miniconda3/envs/py3/lib/python3.7/site-packages/opentrons/protocol_api/transfers.py in <genexpr>(.0)
    562             asp_grouped: List[Tuple[float, Well]] = []
    563             try:
--> 564                 while (sum(a[0] for a in asp_grouped) +
    565                        self._strategy.disposal_volume +
    566                        self._strategy.air_gap +

KeyboardInterrupt:

Current behavior

Simulation runs indefinitely.

Expected behavior

Simulation errors.

@tanaes tanaes added the bug label Jul 17, 2020
@nickcrider nickcrider added the api Affects the `api` project label Jul 21, 2020
@nickcrider
Copy link
Contributor

Thanks for submitting this issue and example code @tanaes we will look into it further.

@SyntaxColoring SyntaxColoring self-assigned this Oct 5, 2020
@SyntaxColoring SyntaxColoring changed the title bug: Inappropriate disposal volume causes hang in transfers.py bug: Inappropriate disposal or air_gap volume causes hang in transfers.py Oct 10, 2020
@SyntaxColoring
Copy link
Contributor

SyntaxColoring commented Oct 10, 2020

Working on this now!

More broadly, this happens if distribute_volume + air_gap + disposal_volume >= pipette_volume. For example, it also happens here:

 pipette_right.distribute(10,
    reagents['A1'],
    samples.wells(),
    disposal_volume=5,
    air_gap=5,
    new_tip='once')

@SyntaxColoring
Copy link
Contributor

This got fixed in PR #13659. The minimal example protocol now prints:

opentrons.protocols.execution.errors.ExceptionInProtocolError: ValueError [line 19]: The disposal volume must be less than the maximum volume of the pipette

Thank you again for this report!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api Affects the `api` project bug robot-svcs Falls under the purview of the Robot Services squad (formerly CPX, Core Platform Experience).
Projects
None yet
5 participants