Ejemplo n.º 1
0
 def emit(scale, unit):
     v = self.value * scale
     if v >= 100:
         return pretty.format('{0:.0n}{1}', v, unit)
     if v >= 10:
         return pretty.format('{0:.1n}{1}', v, unit)
     if v >= 1:
         return pretty.format('{0:.2n}{1}', v, unit)
     return pretty.format('{0:.3n}{1}', v, unit)
Ejemplo n.º 2
0
def verify_well_locations(well_list: List[EnhancedWellV1],
                          pipette: EnhancedPipetteV1):
    picked_tip = False
    if not pipette.tip_attached:
        pipette.pick_up_tip()
        picked_tip = True

    for well in well_list:
        move_to_loc = well.top()
        pipette.move_to(move_to_loc)
        #
        well_top_coords_absolute = well.top_coords_absolute()
        _, top_coords = well_vector(well.top())
        _, move_to_coords = well_vector(move_to_loc)
        intended_coords = well_top_coords_absolute + (move_to_coords -
                                                      top_coords)
        tip_coords = pipette.tip_coords_absolute()
        #
        robot.pause(
            pretty.format('verify location: {0} in {1} loc={2} tip={3}',
                          well.get_name(), well.parent.get_name(),
                          intended_coords, tip_coords))

    if picked_tip:
        pipette.return_tip(
        )  # we didn't dirty it, we can always re-use it todo: enhance return_tip() to adjust iterator so that next pick can pick up again
Ejemplo n.º 3
0
    def __str__(self) -> str:
        def test(v, scale):
            return not is_close(int(v * scale + 0.5), 0)

        def emit(scale, unit):
            v = self.value * scale
            if v >= 100:
                return pretty.format('{0:.0n}{1}', v, unit)
            if v >= 10:
                return pretty.format('{0:.1n}{1}', v, unit)
            if v >= 1:
                return pretty.format('{0:.2n}{1}', v, unit)
            return pretty.format('{0:.3n}{1}', v, unit)

        if self.flavor == Concentration.Flavor.Molar:
            if self.value == 0:
                return emit(1, 'M')
            elif test(self.value, 1):
                return emit(1, 'M')
            elif test(self.value, 1e3):
                return emit(1e3, 'mM')
            elif test(self.value, 1e6):
                return emit(1e6, 'uM')
            elif test(self.value, 1e9):
                return emit(1e9, 'nM')
            elif test(self.value, 1e12):
                return emit(1e12, 'pM')
            else:
                return emit(1e15, 'fM')
        elif self.flavor == Concentration.Flavor.X:
            return pretty.format('{0:.3n}x', self.value)
        else:
            return 'DC'
Ejemplo n.º 4
0
 def done_tip(self):  # a handy little utility that looks at self.config.trash_control
     if self.has_tip:
         if self.get_current_volume() > 0:
             info(pretty.format('{0} has {1:n} uL remaining', self.get_name(), self.get_current_volume()))
         if self.config.trash_control:
             self.drop_tip()
         else:
             self.return_tip()
Ejemplo n.º 5
0
 def __str__(self) -> str:
     if self.is_empty:
         return '{}'
     else:
         result = '{ '
         is_first = True
         total_volume = self.volume
         for liquid, volume in self.liquids.items():
             if not is_first:
                 result += ', '
             if is_scalar(total_volume) and liquid.concentration.flavor != Concentration.Flavor.DontCare:
                 dilution_factor = volume / total_volume
                 concentration = liquid.concentration * dilution_factor
                 result += pretty.format('{0}:{1:n}={2}', liquid.name, volume, concentration)
             else:
                 result += pretty.format('{0}:{1:n}', liquid.name, volume)
             is_first = False
         result += ' }'
     return result
 def formatted(self):
     result = 'well "{0:s}"'.format(self.target.get_name())
     if not getattr(self.target, 'has_labelled_well_name', False):
         if self.liquid is not None:
             result += ' ("{0:s}")'.format(self.liquid)
     result += ':'
     result += pretty.format(' lo={0:n} hi={1:n} cur={2:n} taken={3:n} mix={4:s}\n',
                               self.liquid_volume.lo_volume,
                               self.liquid_volume.hi_volume,
                               self.liquid_volume.current_volume,
                               infimum(self.liquid_volume.hi_volume) - infimum(self.liquid_volume.current_volume),
                               self.mixture.__str__())
     return result
Ejemplo n.º 7
0
    def dwell(self, seconds=0, minutes=0):
        # like delay() but synchronous with the back-end

        msg = pretty.format('Dwelling for {0:n}m {1:n}s', minutes, seconds)

        minutes += int(seconds / 60)
        seconds = seconds % 60
        seconds += float(minutes * 60)

        def do_dwell():
            self.robot.pause()
            self.robot._driver.delay(seconds)
            self.robot.resume()

        log_while_core(msg, do_dwell)
Ejemplo n.º 8
0
    def dwell(self, seconds=0, minutes=0):
        # like delay() but synchronous with the back-end

        msg = pretty.format('Dwelling for {0:n}m {1:n}s', minutes, seconds)

        minutes += int(seconds / 60)
        seconds = seconds % 60
        seconds += float(minutes * 60)

        def do_dwell():
            self.config.protocol_context.pause()
            self._hw_manager.enhanced_hardware().dwell(seconds)
            self.config.protocol_context.resume()

        log_while_core(msg, do_dwell)
Ejemplo n.º 9
0
 def _dispense_plunger_position(self, ul):
     assert tls.dispense_params
     mm_from_vol = super()._dispense_plunger_position(
         ul)  # retrieve position historically used
     if self.config.enable_enhancements and \
             (tls.dispense_params.full_dispense_from_dispense or
              (tls.dispense_params_transfer and tls.dispense_params_transfer.full_dispense_transfer)):
         mm_from_blow = self._get_plunger_position('blow_out')
         info(
             pretty.format(
                 'full dispensing to mm={0:n} instead of mm={1:n}',
                 mm_from_blow, mm_from_vol))
         tls.dispense_params.fully_dispensed = True
         return mm_from_blow
     else:
         tls.dispense_params.fully_dispensed = False
         return mm_from_vol
Ejemplo n.º 10
0
 def _pre_wet(self, well: EnhancedWell, volume, location, rate, pre_wet: bool):
     if pre_wet is None:
         if tls.aspirate_params_transfer:
             pre_wet = tls.aspirate_params_transfer.pre_wet_transfer
     if pre_wet is None:
         pre_wet = self.config.aspirate.pre_wet.default
     if pre_wet and self.config.enable_enhancements:
         if self.tip_wetness is TipWetness.DRY:
             pre_wet_volume = min(
                 self.get_max_volume() * self.config.aspirate.pre_wet.max_volume_fraction,
                 max(volume, well.liquid_volume.available_volume_min))
             pre_wet_rate = self.config.aspirate.pre_wet.rate_func(rate)
             self.tip_wetness = TipWetness.WETTING
             def do_pre_wet():
                 for i in range(self.config.aspirate.pre_wet.count):
                     self.aspirate(volume=pre_wet_volume, location=location, rate=pre_wet_rate, pre_wet=False, ms_pause=0)
                     self.dispense(volume=pre_wet_volume, location=location, rate=pre_wet_rate, full_dispense=(i+1 == self.config.aspirate.pre_wet.count))
             info_while(pretty.format('prewetting tip in well {0} vol={1:n}', well.get_name(), pre_wet_volume), do_pre_wet)
             self.tip_wetness = TipWetness.WET
Ejemplo n.º 11
0
    def plunger_position(self, instr: HwPipette, ul: float, action: str,
                         call_super: Callable) -> float:
        mm_from_vol = call_super()
        result = mm_from_vol

        if action == 'dispense':
            assert tls.dispense_params
            if self.config.enable_enhancements and \
                    (tls.dispense_params.full_dispense_from_dispense or
                     (tls.dispense_params_transfer and tls.dispense_params_transfer.full_dispense_transfer)):
                result = mm_from_blow = instr.config.blow_out
                info(
                    pretty.format(
                        'full dispensing to mm={0:n} instead of mm={1:n}',
                        mm_from_blow, mm_from_vol))
                tls.dispense_params.fully_dispensed = True
            else:
                result = call_super(action)
                tls.dispense_params.fully_dispensed = False

        return result
Ejemplo n.º 12
0
    def createMasterMix():
        if manually_make_master_mix:
            note_liquid(location=master_mix,
                        name='Master Mix',
                        initially=master_mix_vol)

            log('Creating Master Mix')
            info(
                pretty.format(
                    'Master Mix recipe: water={0:n} buffer={1:n} EvaGreen={2:n} total={3:n} (extra={4}%)',
                    master_mix_common_water_vol, master_mix_buffer_vol,
                    master_mix_evagreen_vol, master_mix_vol,
                    100.0 * (mm_overhead_factor - 1)))
            user_prompt('Ensure master mix manually present and mixed')

        else:
            # Mostly just for fun, we put the ingredients for the master mix in a nice warm place to help them melt
            temp_slot = 11
            temp_module = modules_manager.load('tempdeck', slot=temp_slot)
            screwcap_rack = labware_manager.load(
                'opentrons_24_aluminumblock_generic_2ml_screwcap',
                slot=temp_slot,
                label='screwcap_rack',
                share=True,
                well_geometry=IdtTubeWellGeometry)

            buffers = list(zip(screwcap_rack.rows(0), buffer_volumes))
            evagreens = list(zip(screwcap_rack.rows(1), evagreen_volumes))

            for buffer in buffers:
                note_liquid(location=buffer[0],
                            name='Buffer',
                            initially=buffer[1],
                            concentration=buffer_source_concentration)
            for evagreen in evagreens:
                note_liquid(location=evagreen[0],
                            name='Evagreen',
                            initially=evagreen[1],
                            concentration=evagreen_source_concentration)
            note_liquid(location=master_mix, name='Master Mix')

            # Buffer was just unfrozen. Mix to ensure uniformity. EvaGreen doesn't freeze, no need to mix
            p50.layered_mix([buffer for buffer, __ in buffers], incr=2)

            # transfer from multiple source wells, each with a current defined volume
            def transfer_multiple(msg, xfer_vol_remaining, tubes, dest,
                                  new_tip, *args, **kwargs):
                tube_index = 0
                cur_well = None
                cur_vol = 0
                min_vol = 0
                while xfer_vol_remaining > 0:
                    if xfer_vol_remaining < p50_min_vol:
                        warn(
                            "remaining transfer volume of %f too small; ignored"
                            % xfer_vol_remaining)
                        return
                    # advance to next tube if there's not enough in this tube
                    while cur_well is None or cur_vol <= min_vol:
                        if tube_index >= len(tubes):
                            fatal('%s: more reagent needed' % msg)
                        cur_well = tubes[tube_index][0]
                        cur_vol = tubes[tube_index][1]
                        min_vol = max(
                            p50_min_vol,
                            cur_vol / config.
                            min_aspirate_factor_hack,  # tolerance is proportional to specification of volume. can probably make better guess
                            cur_well.geometry.min_aspiratable_volume)
                        tube_index = tube_index + 1
                    this_vol = min(xfer_vol_remaining, cur_vol - min_vol)
                    assert this_vol >= p50_min_vol  # TODO: is this always the case?
                    log('%s: xfer %f from %s in %s to %s in %s' %
                        (msg, this_vol, cur_well, cur_well.parent, dest,
                         dest.parent))
                    p50.transfer(this_vol,
                                 cur_well,
                                 dest,
                                 trash=config.trash_control,
                                 new_tip=new_tip,
                                 **kwargs)
                    xfer_vol_remaining -= this_vol
                    cur_vol -= this_vol

            def mix_master_mix():
                log('Mixing Master Mix')
                p50.layered_mix(
                    [master_mix],
                    incr=2,
                    initial_turnover=master_mix_evagreen_vol * 1.2,
                    max_tip_cycles=config.layered_mix.max_tip_cycles_large)

            log('Creating Master Mix: Water')
            p50.transfer(master_mix_common_water_vol,
                         waterB,
                         master_mix,
                         trash=config.trash_control)

            log('Creating Master Mix: Buffer')
            transfer_multiple(
                'Creating Master Mix: Buffer',
                master_mix_buffer_vol,
                buffers,
                master_mix,
                new_tip='once',
                keep_last_tip=True
            )  # 'once' because we've only got water & buffer in context
            p50.done_tip()  # EvaGreen needs a new tip

            log('Creating Master Mix: EvaGreen')
            transfer_multiple(
                'Creating Master Mix: EvaGreen',
                master_mix_evagreen_vol,
                evagreens,
                master_mix,
                new_tip='always',
                keep_last_tip=True
            )  # 'always' to avoid contaminating the Evagreen source w/ buffer

            mix_master_mix()
Ejemplo n.º 13
0
    def aspirate(self,
                 volume=None,
                 location=None,
                 rate: float = 1.0,
                 pre_wet: bool = None,
                 ms_pause: float = None,
                 top_clearance=None,
                 bottom_clearance=None,
                 manual_liquid_volume_allowance=None):
        if not helpers.is_number(volume):  # recapitulate super
            if volume and not location:
                location = volume
            volume = self._working_volume - self.current_volume
        location = location if location else self.previous_placeable
        well, _ = well_vector(location)

        if top_clearance is None:
            if tls.aspirate_params_transfer:
                top_clearance = tls.aspirate_params_transfer.top_clearance_transfer
            if top_clearance is None:
                top_clearance = self.config.aspirate.top_clearance
        if bottom_clearance is None:
            if tls.aspirate_params_transfer:
                bottom_clearance = tls.aspirate_params_transfer.bottom_clearance_transfer
            if bottom_clearance is None:
                bottom_clearance = self.config.aspirate.bottom_clearance
        if manual_liquid_volume_allowance is None:
            if tls.aspirate_params_transfer:
                manual_liquid_volume_allowance = tls.aspirate_params_transfer.manual_manufacture_tolerance_transfer
            if manual_liquid_volume_allowance is None:
                manual_liquid_volume_allowance = self.config.aspirate.manual_liquid_volume_allowance

        current_liquid_volume = well.liquid_volume.current_volume_min
        needed_liquid_volume = well.geometry.min_aspiratable_volume + volume
        if current_liquid_volume < needed_liquid_volume:
            msg = pretty.format(
                'aspirating too much from well={0} have={1:n} need={2:n}',
                well.get_name(), current_liquid_volume, needed_liquid_volume)
            warn(msg)

        self._pre_wet(well, volume, location, rate, pre_wet)
        location = self._adjust_location_to_liquid_top(
            location=location,
            aspirate_volume=volume,
            top_clearance=top_clearance,
            bottom_clearance=bottom_clearance,
            manual_liquid_volume_allowance=manual_liquid_volume_allowance)

        def call_super():
            super(EnhancedPipette, self).aspirate(volume=volume,
                                                  location=location,
                                                  rate=rate)

        self._update_pose_tree_in_place(call_super)

        self.pause_after_aspirate(ms_pause)

        # finish up todo: what if we're doing an air gap
        well, __ = well_vector(location)
        well.liquid_volume.aspirate(volume)
        if volume != 0:
            self.prev_aspirated_well = well
Ejemplo n.º 14
0
    def _run_transfer_plan(self, tips, plan, **kwargs):
        air_gap = kwargs.get('air_gap', 0)
        touch_tip = kwargs.get('touch_tip', False)
        is_distribute = kwargs.get('mode', 'transfer') == 'distribute'

        total_transfers = len(plan)
        seen_aspirate = False
        assert len(plan) == 0 or plan[0].get(
            'aspirate')  # first step must be an aspirate

        step_info_map = dict()

        with AspirateParamsTransfer(self.config.aspirate):
            with DispenseParamsTransfer(self.config.dispense):

                for i, step in enumerate(plan):
                    aspirate = step.get('aspirate')
                    dispense = step.get('dispense')

                    if aspirate:
                        # *always* record on aspirates so we can test has_disposal_vol on subsequent dispenses
                        have_disposal_vol = self.has_disposal_vol(
                            plan, i, step_info_map, **kwargs)

                        # we might have overspill from a previous transfer.
                        if self.current_volume > 0:
                            info(
                                pretty.format(
                                    'carried over {0:n} uL from prev operation',
                                    self.current_volume))

                        if not seen_aspirate:
                            assert i == 0

                            if kwargs.get('pre_wet', None) and kwargs.get(
                                    'mix_before', None):
                                warn(
                                    "simultaneous use of 'pre_wet' and 'mix_before' is not tested"
                                )

                            if (kwargs.get('allow_overspill',
                                           self.config.allow_overspill_default)
                                    and self.config.enable_enhancements
                                ) and zeroify(self.current_volume) > 0:
                                this_aspirated_well, __ = well_vector(
                                    aspirate['location'])
                                if self.prev_aspirated_well is this_aspirated_well:
                                    if have_disposal_vol:
                                        # try to remove current volume from this aspirate
                                        new_aspirate_vol = zeroify(
                                            aspirate.get('volume') -
                                            self.current_volume)
                                        if new_aspirate_vol == 0 or new_aspirate_vol >= self.min_volume:
                                            aspirate[
                                                'volume'] = new_aspirate_vol
                                            info(
                                                pretty.format(
                                                    'reduced this aspirate by {0:n} uL',
                                                    self.current_volume))
                                            extra = 0  # can't blow out since we're relying on its presence in pipette
                                        else:
                                            extra = self.current_volume - aspirate[
                                                'volume']
                                            assert zeroify(extra) > 0
                                    else:
                                        info(
                                            pretty.format(
                                                "overspill of {0:n} uL isn't for disposal",
                                                self.current_volume))
                                        extra = self.current_volume
                                else:
                                    # different locations; can't re-use
                                    info(
                                        'this aspirate is from location different than current pipette contents'
                                    )
                                    extra = self.current_volume
                                if zeroify(extra) > 0:
                                    # quiet_log('blowing out overspill of %s uL' % format_number(self.current_volume))
                                    self._blowout_during_transfer(
                                        loc=None,
                                        **kwargs)  # loc isn't actually used

                            elif zeroify(self.current_volume) > 0:
                                info(
                                    pretty.format(
                                        'blowing out unexpected overspill of {0:n} uL',
                                        self.current_volume))
                                self._blowout_during_transfer(
                                    loc=None,
                                    **kwargs)  # loc isn't actually used

                        seen_aspirate = True

                        self._add_tip_during_transfer(tips, **kwargs)
                        # Previous blow-out elisions that don't reduce their adjacent aspirates (because they're not
                        # carrying disposal_vols) might eventually catch up with us in the form of blowing the capacity
                        # of the pipette. When they do, we give in, and carry out the blow-out. This still can be a net
                        # win, in that we reduce the overall number of blow-outs. We might be tempted here to reduce
                        # the capacity of the overflowing aspirate, but that would reduce precision (we still *could*
                        # do that if it has disposal_vol, but that doesn't seem worth it).
                        if self.current_volume + aspirate[
                                'volume'] > self._working_volume:
                            info(
                                pretty.format(
                                    'current {0:n} uL with aspirate(has_disposal={1}) of {2:n} uL would overflow capacity',
                                    self.current_volume,
                                    self.has_disposal_vol(
                                        plan, i, step_info_map,
                                        **kwargs), aspirate['volume']))
                            self._blowout_during_transfer(
                                loc=None, **kwargs)  # loc isn't actually used

                        tls.aspirate_params_transfer.sequester(kwargs)
                        self._aspirate_during_transfer(aspirate['volume'],
                                                       aspirate['location'],
                                                       **kwargs)

                    if dispense:
                        if self.current_volume < dispense['volume']:
                            warn(
                                pretty.format(
                                    'current {0:n} uL will truncate dispense of {1:n} uL',
                                    self.current_volume, dispense['volume']))

                        can_full_dispense = self.current_volume - dispense[
                            'volume'] <= 0

                        tls.dispense_params_transfer.sequester(
                            kwargs, can_full_dispense)
                        self._dispense_during_transfer(dispense['volume'],
                                                       dispense['location'],
                                                       **kwargs)

                        do_touch = touch_tip or touch_tip is 0
                        is_last_step = step is plan[-1]
                        if is_last_step or plan[i + 1].get('aspirate'):
                            do_drop = not is_last_step or not (
                                kwargs.get('keep_last_tip', False)
                                and self.config.enable_enhancements)
                            # original always blew here. there are several reasons we could still be forced to blow
                            do_blow = not is_distribute  # other modes (are there any?) we're not sure about
                            do_blow = do_blow or kwargs.get(
                                'blow_out', False)  # for compatibility
                            do_blow = do_blow or do_touch  # for compatibility
                            do_blow = do_blow or not (
                                kwargs.get(
                                    'allow_blow_elision',
                                    self.config.allow_blow_elision_default)
                                and self.config.enable_enhancements)
                            if not do_blow:
                                if is_last_step:
                                    if self.current_volume > 0:
                                        if not (kwargs.get(
                                                'allow_overspill', self.config.
                                                allow_overspill_default
                                        ) and self.config.enable_enhancements):
                                            do_blow = True
                                        elif self.current_volume > kwargs.get(
                                                'disposal_vol', 0):
                                            warn(
                                                pretty.format(
                                                    'carried over {0:n} uL to next operation',
                                                    self.current_volume))
                                        else:
                                            info(
                                                pretty.format(
                                                    'carried over {0:n} uL to next operation',
                                                    self.current_volume))
                                else:
                                    # if we can, account for any overspill in the next aspirate
                                    if self.current_volume > 0:
                                        if self.has_disposal_vol(
                                                plan, i + 1, step_info_map,
                                                **kwargs):
                                            next_aspirate = plan[i + 1].get(
                                                'aspirate')
                                            assert next_aspirate
                                            next_aspirated_well, __ = well_vector(
                                                next_aspirate['location'])
                                            if self.prev_aspirated_well is next_aspirated_well:
                                                new_aspirate_vol = zeroify(
                                                    next_aspirate.get('volume')
                                                    - self.current_volume)
                                                if new_aspirate_vol == 0 or new_aspirate_vol >= self.min_volume:
                                                    next_aspirate[
                                                        'volume'] = new_aspirate_vol
                                                    info(
                                                        pretty.format(
                                                            'reduced next aspirate by {0:n} uL',
                                                            self.current_volume
                                                        ))
                                                else:
                                                    do_blow = True
                                            else:
                                                do_blow = True  # different aspirate locations
                                        else:
                                            # Next aspirate doesn't *want* our overspill, so we don't reduce his
                                            # volume. But it's harmless to just leave the overspill present; might
                                            # be useful down the line
                                            pass
                                    else:
                                        pass  # currently empty
                            if do_touch:
                                self.touch_tip(touch_tip)
                            if do_blow:
                                self._blowout_during_transfer(
                                    dispense['location'], **kwargs)
                            if do_drop:
                                tips = self._drop_tip_during_transfer(
                                    tips, i, total_transfers, **kwargs)
                        else:
                            if air_gap:
                                self.air_gap(air_gap)
                            if do_touch:
                                self.touch_tip(touch_tip)
Ejemplo n.º 15
0
    def aspirate(
            self,
            volume: float = None,
            location: Union[types.Location, EnhancedWellV2] = None,
            rate: float = 1.0,
            # remainder are added params
            pre_wet: bool = None,
            ms_pause: float = None,
            top_clearance=None,
            bottom_clearance=None,
            manual_liquid_volume_allowance=None):

        # figure out where we're aspirating from
        # recapitulate super
        if isinstance(location, WellV2):
            point, well = location.bottom()
            dest = types.Location(
                point + types.Point(0, 0, self.well_bottom_clearance.aspirate),
                well)
        elif isinstance(location, types.Location):
            dest = location
        elif location is not None:
            raise TypeError(
                'location should be a Well or Location, but it is {}'.format(
                    location))
        elif self._ctx.location_cache:
            dest = self._ctx.location_cache
        else:
            raise RuntimeError(
                "If aspirate is called without an explicit location, another method that moves to a  location (such as move_to or dispense) must previously have been called so the robot knows where it is."
            )

        location = dest  # no need for new variable
        assert isinstance(location, types.Location)
        point, well = location

        if top_clearance is None:
            if tls.aspirate_params_transfer:
                top_clearance = tls.aspirate_params_transfer.top_clearance_transfer
            if top_clearance is None:
                top_clearance = self.well_top_clearance.aspirate
        if bottom_clearance is None:
            if tls.aspirate_params_transfer:
                bottom_clearance = tls.aspirate_params_transfer.bottom_clearance_transfer
            if bottom_clearance is None:
                bottom_clearance = self.well_bottom_clearance.aspirate
        if manual_liquid_volume_allowance is None:
            if tls.aspirate_params_transfer:
                manual_liquid_volume_allowance = tls.aspirate_params_transfer.manual_manufacture_tolerance_transfer
            if manual_liquid_volume_allowance is None:
                manual_liquid_volume_allowance = self.config.aspirate.manual_liquid_volume_allowance

        current_liquid_volume = well.liquid_volume.current_volume_min
        needed_liquid_volume = well.geometry.min_aspiratable_volume + volume
        if current_liquid_volume < needed_liquid_volume:
            msg = pretty.format(
                'aspirating too much from well={0} have={1:n} need={2:n}',
                well.get_name(), current_liquid_volume, needed_liquid_volume)
            warn(msg)

        self._pre_wet(well, volume, location, rate, pre_wet)
        location = self._adjust_location_to_liquid_top(
            location=location,
            aspirate_volume=volume,
            top_clearance=top_clearance,
            bottom_clearance=bottom_clearance,
            manual_liquid_volume_allowance=manual_liquid_volume_allowance)

        def call_super():
            super(EnhancedPipette, self).aspirate(volume=volume,
                                                  location=location,
                                                  rate=rate)

        self.use_self_while(call_super)

        self.pause_after_aspirate(ms_pause)

        # finish up todo: what if we're doing an air gap
        well.liquid_volume.aspirate(volume)
        if volume != 0:
            self.prev_aspirated_well = well
Ejemplo n.º 16
0
    def diluteStrands():
        if manually_dilute_strands:
            note_liquid(location=diluted_strand_a,
                        name='Diluted StrandA',
                        initially=strand_dilution_vol)
            note_liquid(location=diluted_strand_b,
                        name='Diluted StrandB',
                        initially=strand_dilution_vol)

            log('Diluting Strands')
            info(
                pretty.format(
                    'Diluted Strand A recipe: water={0:n} strandA={1:n} vol={2:n}',
                    strand_dilution_water_vol, strand_dilution_source_vol,
                    strand_dilution_vol))
            info(
                pretty.format(
                    'Diluted Strand B recipe: water={0:n} strandB={1:n} vol={2:n}',
                    strand_dilution_water_vol, strand_dilution_source_vol,
                    strand_dilution_vol))
            user_prompt('Ensure diluted strands manually present and mixed')

        else:
            strand_a = eppendorf_1_5_rack['A1']
            strand_b = eppendorf_1_5_rack['B1']
            assert strand_a_min_vol >= strand_dilution_source_vol + strand_a.geometry.min_aspiratable_volume
            assert strand_b_min_vol >= strand_dilution_source_vol + strand_b.geometry.min_aspiratable_volume

            note_liquid(location=strand_a,
                        name='StrandA',
                        concentration=strand_a_conc,
                        initially_at_least=strand_a_min_vol
                        )  # i.e.: we have enough, just not specified how much
            note_liquid(location=strand_b,
                        name='StrandB',
                        concentration=strand_b_conc,
                        initially_at_least=strand_b_min_vol)  # ditto
            note_liquid(location=diluted_strand_a, name='Diluted StrandA')
            note_liquid(location=diluted_strand_b, name='Diluted StrandB')

            # We used to auto-mix, but now, even when auto-diluting, we rely on user to have mixed on the vortexer
            # p50.layered_mix([strand_a])
            # p50.layered_mix([strand_b])

            # Create dilutions of strands
            log('Moving water for diluting Strands A and B')
            p50.transfer(
                strand_dilution_water_vol,
                waterA,
                [diluted_strand_a, diluted_strand_b],
                new_tip=
                'once',  # can reuse for all diluent dispensing since dest tubes are initially empty
                trash=config.trash_control)
            log('Diluting Strand A')
            p50.transfer(strand_dilution_source_vol,
                         strand_a,
                         diluted_strand_a,
                         trash=config.trash_control,
                         keep_last_tip=True)
            p50.layered_mix([diluted_strand_a])

            log('Diluting Strand B')
            p50.transfer(strand_dilution_source_vol,
                         strand_b,
                         diluted_strand_b,
                         trash=config.trash_control,
                         keep_last_tip=True)
            p50.layered_mix([diluted_strand_b])
for i in range(num_masses):
    vol = (i + 1) * mass_incr_vol
    for j in range(num_replicates):
        well = eppendorf_1_5_rack.cols(i).wells(j)
        well.mass_vol = vol
        mass_wells.append(well)

for well in mass_wells:
    Eppendorf1Point5MlTubeGeometry(well)

log('Liquid Names')
note_liquid(location=water, name='Water',
            initially_at_least=15000)  # volume is rough guess
for well in mass_wells:
    note_liquid(location=well,
                name=pretty.format('mass_vol={0:n}', well.mass_vol))

# Clean up namespace
del well, i, j

########################################################################################################################
# Off to the races
########################################################################################################################

for well in mass_wells:
    p.transfer(well.mass_vol,
               water,
               well,
               new_tip='once',
               trash=config.trash_control,
               allow_blow_elision=True,
Ejemplo n.º 18
0
    def _layered_mix_one(self, well: EnhancedWellV1, msg, **kwargs):
        def fetch(name, default=None):
            if default is None:
                default = getattr(self.config.layered_mix, name, None)
            result = kwargs.get(name, default)
            if result is None:
                result = default  # replace any explicitly stored 'None' with default
            return result

        count = fetch('count')
        min_incr = fetch('min_incr')
        incr = fetch('incr')
        count_per_incr = fetch('count_per_incr')
        volume = fetch('volume', self.get_max_volume())
        ms_pause = fetch('ms_pause')
        ms_final_pause = fetch('ms_final_pause')
        aspirate_rate = fetch('aspirate_rate', self.config.layered_mix.aspirate_rate_factor)
        dispense_rate = fetch('dispense_rate', self.config.layered_mix.dispense_rate_factor)
        initial_turnover = fetch('initial_turnover')
        max_tip_cycles = fetch('max_tip_cycles', infinity)
        pre_wet = fetch('pre_wet', False)  # not much point in pre-wetting during mixing; save some time, simpler. but we do so if asked
        top_clearance = fetch('top_clearance')
        bottom_clearance = fetch('bottom_clearance')

        current_liquid_volume = well.liquid_volume.current_volume_min
        liquid_depth = well.geometry.liquid_depth_from_volume(current_liquid_volume)
        liquid_depth_after_asp = well.geometry.liquid_depth_from_volume(current_liquid_volume - volume)
        msg = pretty.format("{0:s} well='{1:s}' cur_vol={2:n} well_depth={3:n} after_aspirate={4:n}", msg, well.get_name(), current_liquid_volume, liquid_depth, liquid_depth_after_asp)

        def do_one():
            count_ = count
            y_min = y = bottom_clearance
            y_max = self._top_clearance(liquid_depth=liquid_depth_after_asp, clearance=top_clearance)
            if count_ is not None:
                if count_ <= 1:
                    y_max = y_min
                    y_incr = 1  # just so we only go one time through the loop
                else:
                    y_incr = (y_max - y_min) / (count_-1)
                    y_incr = max(y_incr, min_incr)
            else:
                assert incr is not None
                y_incr = incr

            def do_layer(y_layer):
                return y_layer <= y_max or is_close(y_layer, y_max)
            first = True
            tip_cycles = 0
            looped = False
            while do_layer(y):
                looped = True
                if not first and ms_pause > 0:
                    self.dwell(seconds=ms_pause / 1000.0)  # pause to let dispensed liquid disperse
                #
                if first and initial_turnover is not None:
                    count_ = int(0.5 + (initial_turnover / volume))
                    count_ = max(count_, count_per_incr)
                else:
                    count_ = count_per_incr
                if not self.has_tip:
                    self.pick_up_tip()

                radial_clearance_func = self.radial_clearance_manager.get_clearance_function(self, well)
                radial_clearance = 0 if radial_clearance_func is None or not self.config.layered_mix.enable_radial_randomness else radial_clearance_func(y_max)
                radial_clearance = max(0, radial_clearance - max(well.geometry.radial_clearance_tolerance, self.config.layered_mix.radial_clearance_tolerance))

                for i in range(count_):
                    tip_cycles += 1
                    need_new_tip = tip_cycles >= max_tip_cycles
                    full_dispense = need_new_tip or (not do_layer(y + y_incr) and i == count_ - 1)

                    theta = random.random() * (2 * math.pi)
                    _, dispense_coordinates = well.bottom(y_max)
                    random_offset = (radial_clearance * math.cos(theta), radial_clearance * math.sin(theta), 0)
                    dispense_location = (well, dispense_coordinates + random_offset)

                    self.aspirate(volume, well.bottom(y), rate=aspirate_rate, pre_wet=pre_wet)
                    self.move_to(well.bottom(y_max))  # ascend vertically from aspirate location
                    self.dispense(volume, dispense_location, rate=dispense_rate, full_dispense=full_dispense)
                    self.move_to(well.bottom(y_max))  # prepare for vertical descent on a subsequent aspirate

                    if need_new_tip:
                        self.done_tip()
                        tip_cycles = 0
                #
                y += y_incr
                first = False
            if looped and ms_final_pause > 0:
                self.dwell(seconds=ms_final_pause / 1000.0)

        info_while(msg, do_one)