def add_antibody(protocol: ProtocolContext,
                 p300_multi: InstrumentContext,
                 reservoir: Labware,
                 tuberack: Labware,
                 plate: Labware,
                 wells: [[]]):
    """

    Args:
        protocol:
        p300_multi:
        reservoir: hopefully we will get a 12 well trough
        tuberack:
        wells: a column-wise list of lists of wells in use

    Returns:
        Nothing as of now

    """

    #  move liquid from reservoir to plate with p300 multi
    for _ in wells:
        i = 0
        p300_multi.transfer(source=reservoir, dest=plate.columns()[i], new_tip='never')
        i += 1
    #  pause for 2 hours
    protocol.delay(minutes=120)
Exemple #2
0
    def pick_up(pipette: InstrumentContext):
        """`pick_up()` will pause the ctx when all tip boxes are out of
        tips, prompting the user to replace all tip racks. Once tipracks are
        reset, the ctx will start picking up tips from the first tip
        box as defined in the slot order when assigning the labware definition
        for that tip box. `pick_up()` will track tips for both pipettes if
        applicable.

        :param pipette: The pipette desired to pick up tip
        as definited earlier in the ctx (e.g. p300, m20).
        """
        for i, rack in enumerate(tip_map):
            # Check the flag to see if the rack is empty, then we don't loop
            # through that rack so that the algorithm executes faster.
            if rack[-1] is False:
                if i == len(tip_map) - 1:  # All tips are used, time to reset
                    ctx.pause("Replace empty tip racks")
                    # print("Replace empty tip racks")
                    pipette.reset_tipracks()
                    for rack in tip_map:
                        rack[-1] = True
                    # Raise an exception so that we can retry the pick up
                    raise OutOfTipsError(
                        "Tipracks were out of tips and were reset")
                else:
                    continue
            for column in rack[:-1]:  # skip [-1] index because it's the flag
                for well in column:
                    if well.has_tip:
                        pipette.pick_up_tip(well)
                        if well.well_name == 'A12':  # last tip in the rack
                            rack[-1] = False
                        return
Exemple #3
0
def distribute_mm_to_map(p50s: InstrumentContext, plates: [Labware],
                         tuberack: Labware, tipracks: [Labware], facs: Labware,
                         groups: typing.Generator, platemap: list,
                         protocol: protocol_api.ProtocolContext):

    tubes = tuberack.wells()[:3]
    plate = plates[0]
    next(groups)
    # for plate in plates:
    for tube in tubes:
        current_group = next(groups)
        map_row_counter = 0
        p50s.pick_up_tip()
        for row in plate.rows():
            map_row = platemap[map_row_counter]
            for i in range(12):
                if map_row[i] == current_group and map_row[i] != '':
                    p50s.well_bottom_clearance.aspirate = 10
                    p50s.aspirate(volume=50, location=tube)
                    p50s.well_bottom_clearance.dispense = 10
                    p50s.dispense(volume=50, location=row[i])
                else:
                    pass
            map_row_counter += 1
        p50s.drop_tip()
def distribute_mm_to_map(p50s: InstrumentContext, plates: [Labware],
                         tuberack: Labware,
                         protocol: protocol_api.ProtocolContext,
                         groups: typing.Generator, platemap: list, volume):

    tubes = tuberack.wells()[:6]
    # next(groups)
    for i in range(len(plates)):
        current_plate = plates[i]
        if i > len(plates) / 2:
            p50s.well_bottom_clearance.aspirate = .8
        else:
            p50s.well_bottom_clearance.aspirate = 1
        for tube in tubes:
            current_group = next(groups)
            map_row_counter = 0
            p50s.pick_up_tip()
            for row in current_plate.rows():
                map_row = platemap[map_row_counter]
                for i in range(12):
                    if map_row[i] == current_group and map_row[i] != '':
                        # p50s.well_bottom_clearance.aspirate = .2
                        p50s.aspirate(volume=volume, location=tube)
                        # p50s.well_bottom_clearance.dispense = 8
                        p50s.dispense(volume=volume, location=row[i])
                    else:
                        pass
                map_row_counter += 1
            p50s.drop_tip()
        protocol.pause("Remove plate and press Resume to continue")
    def wash(pip: InstrumentContext,
             vol: float,
             source: VolTracker,
             dest: list,
             do_dry_run: bool = False,
             pip_offset: float = 0,
             steps: int = 5,
             do_reuse_tip: bool = False):
        """ This function is used to aspirate a washing buffer and then
        dispense it over a well using a moving dispense

        :param pip: The pipette to use for washing aspirations/dispenses
        :param vol: The volume to wash with, e.g. 4000 uL
        :param source: VolTracker tracking a labware source of wash buffer,
        e.g. a reservoir
        :param dest: A list of wells to dispense to
        :param do_dry_run: If this argument is true then pipette tips will be
        returned to the rack they come from.
        :param pip_offset: Millimeter offset from the bottom of the well
        (i.e. the Shandon coverplate mouth)
        :param do_reuse_tip: Use only one tip for aspirating PBS / Washing
        each slide well?
        """
        max_vol = pip.max_volume
        vol_backup = vol
        for well in dest:
            if not pip.has_tip:
                pick_up(pip)
            while vol > 0:
                aspiration_vol = vol if vol < max_vol else max_vol
                pip.aspirate(aspiration_vol, source.track(aspiration_vol))
                dispense_while_moving(pip, well, aspiration_vol, steps,
                                      verbose, pip_offset)
                vol -= aspiration_vol
            if do_dry_run and not do_reuse_tip:
                pip.return_tip()
            elif not do_reuse_tip:
                pip.drop_tip()
            vol = vol_backup
        if do_reuse_tip and not do_dry_run:
            pip.drop_tip()
        elif do_dry_run and pip.has_tip:
            pip.return_tip()
Exemple #6
0
def distribute_master_mix(p300m: InstrumentContext, plates: [Labware],
                          tuberack: Labware, tipracks: [Labware]):
    tubes = tuberack.wells()[0:4]
    p300m.well_bottom_clearance.dispense = .02
    tip_counter = 0
    # to_remove is the number of wells to be removed from the final row. all prior rows will be assumed to be filled
    to_remove = 11
    to_remove = 12 - to_remove
    # last_row is the index of the last row (rows() returns 2D list of rows by well)
    last_row = 1
    plate = plates[0]
    # for plate in plates:
    wells = plate.rows()[:2]
    wells[last_row] = wells[last_row][:to_remove]
    # for example, pop the last 8 in a row for a
    # for plate in plates:
    #     # last_row is the index of the last row (rows() returns 2D list of rows by well)
    #
    #     plate = plates[0]
    #     # for plate in plates:
    #     wells = plate.rows()[:2]
    #     wells[last_row] = wells[last_row][:to_remove]
    group_counter = 0
    tip_gen = next_tip(p300m.tip_racks, 1)
    for tube in tubes:
        p300m.well_bottom_clearance.aspirate = .1
        print(wells)
        wells = plate.rows()[:2 + group_counter]
        group_counter += 2
        wells[last_row] = wells[last_row][:to_remove]
        for row in wells:
            for well in row:
                tip = next(tip_gen)
                print(tip)
                p300m.pick_up_tip(location=tip, presses=2, increment=.05)
                print(tube, well)
                p300m.aspirate(volume=100, location=tube)
                p300m.dispense(volume=100, location=well)
                p300m.well_bottom_clearance.aspirate = .02
                p300m.mix(volume=60, repetitions=3, location=well)
                p300m.drop_tip()
                tip_counter += 1
 def dispense_while_moving(pip: InstrumentContext,
                           well: Well,
                           vol: float,
                           steps: int,
                           is_verbose: bool = False,
                           pip_offset: float = 0):
     """
     This function dispenses a partial volume = vol/steps and then moves
     a distance/steps and repeats
     """
     well_diameter = float(well.diameter)
     dispense_distance = well_diameter - well_edge_offset
     dy = dispense_distance / steps  # Move a fraction (=steps) of well diatr.
     dv = vol / steps
     start_location = well.bottom().move(
         Point(0, well_diameter / 2 - well_edge_offset, pip_offset))
     pip.move_to(start_location)
     for i in range(steps):
         loc = start_location.move(Point(0, i * dy, 0))
         if is_verbose:
             ctx.comment("Dispensing at: {}".format(loc))
         pip.dispense(dv, loc)
Exemple #8
0
 def mix(pipette: InstrumentContext, n_mixes, vol, location):
     if n_mixes == 0:
         return
     else:
         pipette.mix(n_mixes, vol, location)
Exemple #9
0
def distribute_master_mix_p50(p50s: InstrumentContext, plates: [Labware],
                              tuberack: Labware, tipracks: [Labware],
                              facs: Labware):
    tubes = tuberack.wells()[:2]
    # to_remove is the number of wells to be removed from the final row. all prior rows will be assumed to be filled
    to_remove = 6
    to_remove = 12 - to_remove
    p50s.well_bottom_clearance.dispense = 10
    p50s.well_bottom_clearance.aspirate = 3
    # last_row is the index of the last row (rows() returns 2D list of rows by well)
    for plate in plates:
        start_row = 0
        num_rows = 2
        # first group @ row 0 (row A)
        last_row = num_rows
        for tube in tubes:
            group = plate.rows()[start_row:last_row]
            last_group = group[num_rows - 1][:to_remove]
            group[num_rows - 1] = last_group
            p50s.pick_up_tip()
            p50s.transfer(
                volume=50,
                source=tube,
                dest=group,
                new_tip='never',
            )  # comment out for actual runs. this is for test
            p50s.drop_tip()
            p50s.pick_up_tip()
            p50s.transfer(volume=50,
                          source=facs['A1'],
                          dest=group,
                          new_tip='never'
                          )  # comment out for actual runs. this is for test
            p50s.drop_tip()
            start_row += num_rows
            last_row += num_rows
Exemple #10
0
def elisa_wash(protocol: protocol_api.ProtocolContext,
               p300m: InstrumentContext,
               reservoir: [Labware],
               plate: Labware,
               num_washes: int,
               wash_volume: int):
    """
    TODO: consider splitting into a load function and a remove function? this one is large. Is that modularity useful?
    # Maybe modularity is useful for multiple plates? Rather than changing this function to accommodate multiple plates
    # TODO: modularity here is almost certainly useful. Can reuse funcs for FACs prep
    Args:
        protocol: From robot
        p300m: P300 multichannel
        reservoir: A 12 well trough containing ELISA wash buffer
        plate: The plate to be washed
        num_washes: number of plate washes to perform
        wash_volume: volume of buffer to wash each well with

    Returns:
        nothing

    """
    # dispenses per aspiration to minimize movement and counter initialization
    dispenses_per_load = int(300/wash_volume)
    # Calculate extra volume
    well_counter = 0
    vol_counter = 0
    # Pick up tips
    # TODO: adjust num presses and increment
    p300m.pick_up_tip(p300m.tip_racks[0].well('A1'), presses=2, increment=.05)
    for i1 in range(num_washes):
        # reset aspiration height

        index = 0
        # TODO: add disposal volume?
        """
        ~~~~~~~~~~~~~~~~~~
        Handle adding wash to plate. Calculate max number of dispenses per source load.
        Loop and increment index appropriately. This calculation would be automatic, 
        but volume removed from source well has to be tracked manually to prevent empty.
        ~~~~~~~~~~~~~~~~~~
        """
        for i2 in range(int(12/(dispenses_per_load))):
            # Establish a source well. well_counter should increment before well runs out of liquid
            # src must be established within this loop
            if vol_counter >= 9.7:
                # If most of the volume from the trough is gone, move to next well and reset volume count
                well_counter += 1
                vol_counter = 0
            src = reservoir[0].columns()[well_counter]
            wells = plate.rows()[0][index: index+dispenses_per_load]
            # TODO: figure out volume count problem...works but not soon enough. well_counter iterates after two washes
            # TODO: maybe tips don't go down to bottom of well and that's why?
            p300m.well_bottom_clearance.aspirate = 5
            p300m.well_bottom_clearance.dispense = 10
            p300m.distribute(volume=wash_volume, source=src, dest=wells,
                             new_tip='never', disposal_volume=0, blow_out=True)
            # Increment index by number of dispenses per aspiration
            index += dispenses_per_load
            # Count volume consumed from current trough well
            vol_counter += (.3 * 4)

            # Tried distribute and keep getting tip already attached or tip not attached error
        """
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        Mix and dispense most of the liquid into the trash. Manual flicking still necessary.
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        """
        # protocol.delay(seconds=30)
        # # Set clearance for tip for aspiration
        # p300m.well_bottom_clearance.aspirate = 0.1
        # # Mix and transfer volume from plate to trash.
        # p300m.transfer(volume=wash_volume, source=plate.rows()[0],
        #                dest=p300m.trash_container.wells(0), disposal_volume=wash_volume,
        #                new_tip='never',) #mix_before=(2, (wash_volume*.75)), aspirate_speed=5, dispense_speed=12,

        p300m.home()
        protocol.pause(msg="{} washes done! Resume washing by clicking the 'Resume' button!".format(i1+1))
    protocol.comment("{} washes complete! You may proceed with your protocol.".format(num_washes))
    p300m.return_tip()
    p300m.home()
def elisa_wash(protocol: protocol_api.ProtocolContext,
               p300m: InstrumentContext, reservoir: [Labware], plate: Labware,
               wells_to_fill: [[]], num_washes: int, wash_volume: int):
    """
    TODO: consider splitting into a load function and a remove function? this one is large. Is that modularity useful?
    # Maybe modularity is useful for multiple plates? Rather than changing this function to accommodate multiple plates
    # TODO: modularity here is almost certainly useful. Can reuse funcs for FACs prep
    Args:
        protocol: From robot
        p300m: P300 multichannel
        reservoir: A 12 well trough containing ELISA wash buffer
        plate: The plate to be washed
        num_washes: number of plate washes to perform
        wash_volume: volume of buffer to wash each well with

    Returns:
        nothing

    """
    # dispenses per aspiration to minimize movement and counter initialization
    dispenses_per_load = int(300 / wash_volume)
    # Calculate extra volume
    well_counter = 0
    vol_counter = 0
    # Pick up tips
    # TODO: adjust num presses and increment
    p300m.pick_up_tip(p300m.tip_racks[0].well('A1'), presses=3, increment=.05)
    for i1 in range(num_washes):
        # reset aspiration height
        p300m.well_bottom_clearance.aspirate = 1
        index = 0
        # TODO: add disposal volume?
        """
        ~~~~~~~~~~~~~~~~~~
        Handle adding wash to plate. Calculate max number of dispenses per source load.
        Loop and increment index appropriately. This calculation would be automatic, 
        but volume removed from source well has to be tracked manually to prevent empty.
        ~~~~~~~~~~~~~~~~~~
        """
        # for i2 in range(int(12/(dispenses_per_load))):
        # Establish a source well. well_counter should increment before well runs out of liquid
        # src must be established within this loop
        src = reservoir[0].columns()[well_counter]
        # location is a list of pairs defining locations of wells
        location = wells_to_fill

        print("location{}".format(location))
        # subset to locations in the distribution range (number of dispenses per aspiration)
        locs = location[index:index + 3]
        print(locs)
        # for all lists in locs, take the second (1) index aka the row
        # rows = plate.wells(*locs[2])
        # if multiple rows entered into parentheses, each row returned will be a list
        # so plate.row(1) yields [[wells B1-B12]] and plate.rows(1,2) yields [[wells B1-12], [C1-12]]
        """
        The logic below should underlie transforming csv files created by the plate mapper 
        into a format to access plate wells
        """
        rows = []
        cols = []
        for i in location:
            cols.append(i[0])
            if i[1] not in rows:
                rows.append(i[1])
        plate_map = plate.rows(*rows)
        updated = []
        for i in plate_map:
            # there shouldnt be a +1 for normal list slicing but apparently slicing is noninclusive or something
            updated.append(i[min(cols):max(cols) + 1])
        print(updated)

        # TODO: figure out volume count problem...works but not soon enough. well_counter iterates after two washes
        # TODO: maybe tips don't go down to bottom of well and that's why?
        for i in cols:
            p300m.distribute(volume=wash_volume,
                             source=src,
                             dest=rows[i],
                             new_tip='never',
                             disposal_volume=0,
                             blow_out=True)
        # Increment index by number of dispenses per aspiration
        index += dispenses_per_load
        # Count volume consumed from current trough well
        vol_counter += (.3 * 8)
        if vol_counter >= 9.7:
            # If most of the volume from the trough is gone, move to next well and reset volume count
            well_counter += 1
            vol_counter = 0
        # Tried distribute and keep getting tip already attached or tip not attached error
    """
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Mix and dispense most of the liquid into the trash. Manual flicking still necessary.
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    """
    # Set clearance for tip for aspiration
    p300m.well_bottom_clearance.aspirate = 0.1
    # Mix and transfer volume from plate to trash.
    p300m.transfer(
        volume=wash_volume,
        source=plate.rows()[0],
        dest=p300m.trash_container.wells(0),
        disposal_volume=100,
        new_tip='never',
        mix_before=(2, 80),
        aspirate_speed=5,
        dispense_speed=12,
    )
    p300m.home()
    protocol.pause(
        msg="{} washes done! Resume washing by clicking the 'Resume' button!".
        format(i1 + 1))
    protocol.comment(
        "{} washes complete! You may proceed with your protocol.".format(
            num_washes))
    p300m.return_tip()
    p300m.home()