예제 #1
0
def run_custom_protocol(
    volumes_csv: FileInput = example_csv,
    pipette_axis: StringSelection('B (left side)',
                                  'A (right side)') = 'B (left side)',
    pipette_model: StringSelection('p200', 'p100', 'p50', 'p20', 'p10',
                                   'p1000') = 'p200',
    plate_type: StringSelection('96-flat', '384-plate') = '96-flat',
    tip_reuse: StringSelection('new tip each time',
                               'reuse tip') = 'new tip each time'):

    pipette_max_vol = int(pipette_model[1:])

    pipette = instruments.Pipette(axis='b' if pipette_axis[0] == 'B' else 'a',
                                  max_volume=pipette_max_vol,
                                  min_volume=pipette_max_vol / 10,
                                  tip_racks=tipracks,
                                  trash_container=trash)

    plate = containers.load(plate_type, 'A1')

    volumes = [float(cell) for cell in well_csv_to_list(volumes_csv)]

    for vol in volumes:
        if 0 < vol < pipette.min_volume:
            robot.comment(
                'WARNING: volume {} is below pipette\'s minimum volume.'.
                format(vol))

    tip_strategy = 'always' if tip_reuse == 'new tip each time' else 'once'
    pipette.transfer(volumes, source, plate, new_tip=tip_strategy)
예제 #2
0
def note_liquid(location, name=None, initially=None, initially_at_least=None, concentration=None, local_config=None):
    # Must keep in sync with Opentrons-Analyze analyze_liquid_name

    if local_config is None:
        local_config = rgatkinson.configuration.config

    well, __ = well_vector(location)
    if name is None:
        name = well.label
    else:
        well.label = name

    liquid = local_config.execution_context.liquids.get_liquid(name)

    d = {'name': name, 'location': get_location_path(well)}

    if initially is not None and initially_at_least is not None:
        raise ValueError  # can't use both at once

    initially = LiquidVolume.fix_initially(initially)

    if initially is None and initially_at_least is not None:
        initially = Interval([initially_at_least, well.geometry.well_capacity])

    if initially is not None:
        d['initially'] = initially
        well.liquid_volume.set_initially(initially)

    if concentration is not None:
        concentration = Concentration(concentration)
        liquid.concentration = concentration
        d['concentration'] = str(concentration)

    serialized = json.dumps(d).replace("{", "{{").replace("}", "}}")  # runtime calls comment.format(...) on our comment; avoid issues therewith
    robot.comment('Liquid: %s' % serialized)
예제 #3
0
def transformation_setup(transformation_wells):
    """Sets up transformation reactions

    Args:
    transformation_wells (list). 

    """

    # Constants
    TEMP = 4  # Incubation temperature.
    ASSEMBLY_VOL = 5  # Volume of final assembly added to competent cells.
    MIX_SETTINGS = (4, 5)  # Mix after setting during final assembly transfers.
    INCUBATION_TIME = 20  # Cells and final assembly incubation time.

    # Set temperature deck to 4 °C and load competent cells
    tempdeck.set_temperature(TEMP)
    tempdeck.wait_for_temp()
    robot.pause()
    robot.comment('Load competent cells, uncap and resume run')

    # Transfer final assemblies
    p10_pipette.transfer(ASSEMBLY_VOL,
                         assembly_plate.wells(transformation_wells),
                         transformation_plate.wells(transformation_wells),
                         new_tip='always',
                         mix_after=(MIX_SETTINGS))

    # Incubate for 20 minutes and remove competent cells for heat shock
    p10_pipette.delay(minutes=INCUBATION_TIME)
    robot.pause()
    robot.comment(
        'Remove transformation reactions, conduct heatshock and replace.')
예제 #4
0
def robot_wait():

    if not robot.is_simulating():
       robot.comment("Waiting...")
       robot._driver.turn_on_red_button_light()
       while not robot._driver.read_button():
          sleep(0.5)

       robot._driver.turn_on_blue_button_light()
예제 #5
0
def phase_switch(comment='Remove final assembly plate. Introduce agar tray and deep well plate containing SOC media. Resume run.'):
    """Function pauses run enabling addition/removal of labware.

    Args:
    comment (str): string to be displayed during run following pause.

    """
    robot.pause()
    robot.comment(comment)
예제 #6
0
def robot_wait_tiprack():

    if not robot.is_simulating():
        robot.comment("Waiting...")
        set_button_light(blue=True, red=True, green=True)
        while not robot._driver.read_button():
            sleep(0.5)

        robot._driver.turn_on_blue_button_light()
예제 #7
0
def robot_wait_tiprack():

    if not robot.is_simulating():
        robot.comment("Waiting...")
        os.system('/data/startpwm 1 1 1 16')
        while not robot._driver.read_button():
            sleep(0.5)

        os.system('/data/stoppwm')
        robot._driver.turn_on_blue_button_light()
예제 #8
0
def nonconstant_vol_procedure(small_pipette, large_pipette, small_volume,
                              less_than_crit_well, volume, large_min_volume,
                              sol_pos, well_pos, small_condition):
    if small_volume == less_than_crit_well:  #ie: distribute this this iteration
        if (volume < large_min_volume) and (volume != 0):
            allot(small_pipette, volume, sol_pos, well_pos, small_condition)
        elif (volume == 0):
            robot.comment("0ul. Nothing is done.")
        else:
            allot(large_pipette, volume, sol_pos, well_pos, small_condition)
def run_custom_protocol():
    p50_single = instruments.P50_Single(mount='right', tip_racks=[tiprack])

    transfer_volume = 50
    initial_volume = 2000  # Initial volume held in source tube

    source_tube = tube_rack_2ml.wells('D3')
    destination_tube = tube_rack_2ml.wells('D4')

    remaining_vol = 2000
    height = 1  # Initial height within source tube
    source_height_offset = 0.5  # Offset so that pipette tip is slightly submerged in source tube, not hovering at surface
    source_height = height - source_height_offset
    p50_single.pick_up_tip()
    while remaining_vol > 0:
        robot.comment(
            str(source_height))  # Print out the current source_height

        # This transfer command will start pipetting from the top of the source tube to the bottom of the destination
        # tube, and will continue "tracking" the height of the two volumes in each tube
        source = (source_tube,
                  source_tube.from_center(x=0, y=0, z=source_height)
                  )  # locations are tuples
        destination = (destination_tube,
                       destination_tube.from_center(x=0, y=0, z=-height)
                       )  # locations are tuples
        p50_single.transfer(transfer_volume,
                            source,
                            destination,
                            disposal_vol=0,
                            blow_out=True,
                            new_tip='never')

        # Update height by subtracting ratio of transfer_vol:inital_vol, or set to bottom of tube is "below" bottom
        if height > -1:
            height -= (
                transfer_volume / initial_volume
            ) * 2  # x2 because tube size is -1 to 1 i.e. a difference of 2
        else:
            height = -1

        # Update source_height or set to bottom of tube
        source_height = height - source_height_offset
        if source_height < -1:
            source_height = -1

        # Update remaining volume
        remaining_vol -= transfer_volume
예제 #10
0
def robot_wait(func=None, timer=None):

    # You can specify a function to run <timer> minutes after the robot starts waiting
    if func is not None:
        if robot.is_simulating():
            func()
        start_time = perf_counter()
        duration = 60 * timer
        started = False

    if not robot.is_simulating():
        robot.comment("Waiting...")
        robot._driver.turn_on_red_button_light()
        while not robot._driver.read_button():
            if func is not None and not started:
                now = perf_counter()
                if now - start_time > duration:
                    started = True
                    func()
            sleep(0.5)

        robot._driver.turn_on_blue_button_light()
예제 #11
0
def run_custom_protocol(
    volumes_csv: FileInput = example_csv,
    pipette_mount: StringSelection('right', 'left') = 'right',
    pipette_model: StringSelection('p300-Single', 'p50-Single',
                                   'p10-Single') = 'p300-Single',
    plate_type: StringSelection('96-flat', '384-plate') = '96-flat',
    tip_reuse: StringSelection('new tip each time',
                               'reuse tip') = 'new tip each time'):
    tipracks = [
        labware.load('opentrons-tiprack-300ul', slot) for slot in tiprack_slots
    ]

    if pipette_model == 'p300-Single':
        pipette = instruments.P300_Single(mount=pipette_mount,
                                          tip_racks=tipracks)
    elif pipette_model == 'p50-Single':
        pipette = instruments.P50_Single(mount=pipette_mount,
                                         tip_racks=tipracks)
    elif pipette_model == 'p10-Single':
        tipracks = [
            labware.load('tiprack-10ul', slot) for slot in tiprack_slots
        ]
        pipette = instruments.P10_Single(mount=pipette_mount,
                                         tip_racks=tipracks)

    plate = labware.load(plate_type, '3')

    volumes = [float(cell) for cell in well_csv_to_list(volumes_csv)]

    for vol in volumes:
        if 0 < vol < pipette.min_volume:
            robot.comment(
                'WARNING: volume {} is below pipette\'s minimum volume.'.
                format(vol))

    tip_strategy = 'always' if tip_reuse == 'new tip each time' else 'once'
    pipette.transfer(volumes, source, plate, new_tip=tip_strategy)
예제 #12
0
def washSamples(numWashes, volWash):
    robot.comment("Beginning " + str(numWashes) + " washes, " + str(volWash) +
                  " µl each.")
    numWashes = 3
    volWash = 300
    for washing in range(0, numWashes):
        for row in range(0, sampleRows):
            p300_multi_default_speed.transfer(volWash,
                                              washBasin.rows(row),
                                              samplePlate.rows(row),
                                              new_tip='never',
                                              blow_out=True,
                                              touch_tip=False)
        for row in range(0, sampleRows):
            p300_multi_default_speed.transfer(
                volWash,
                samplePlate.rows(row).bottom(aspHeight),
                wastePlate.rows(row),
                new_tip='never',
                blow_out=True)
        robot.comment("Finished wash number " + str(washing + 1) + " of " +
                      str(numWashes) + " washes.\n")
    robot.comment("Finished washing " + str(numWashes) +
                  " times. Adding low glucose solution to wells now.\n")
예제 #13
0
    P10.pick_up_tip()
    for well_counter, values in enumerate(
            reagent
    ):  # Specifies the well position and the volume of reagent being
        if values == float(0):
            pass
        elif values < float(30):  # transfered in
            P10.distribute(  # If volume below 30, P10 used not p300, if over P300 used
                values,
                Buffers2(source).top(-70),
                well_buffers96(well_counter).top(0.5),
                blow_out=True,
                rate=0.5,
                new_tip='never')
            P10.touch_tip(well_buffers96(well_counter))
            P10.blow_out(well_buffers96(well_counter))
        else:
            P300.distribute(values,
                            Buffers2(source),
                            well_buffers96(well_counter).top(0.5),
                            blow_out=True,
                            rate=0.5,
                            new_tip='never')
            P300.touch_tip(well_buffers96(well_counter))
            P300.blow_out(well_buffers96(well_counter))
    P300.drop_tip(
    )  # Drops tips at end of single reagent run to prevent contamination
    P10.drop_tip()

robot.comment("Protocol finished")
예제 #14
0
sample_number = 96
col_num = sample_number // 8 + (1 if sample_number % 8 > 0 else 0)
samples = [col for col in temp_plate.cols()[:col_num]]

## Volume setup
#ER_vol = 5.85
Lig_vol = 6
#Fill_vol = 10
#MM_dist_ER = ER_vol * col_num
MM_dist_Lig = Lig_vol * col_num
#MM_dist_Fill = Fill_vol * col_num

"""
Ligase
"""
robot.comment("Yay! \ Ligase begins.")

temp_deck_1.set_temperature(10)
temp_deck_2.set_temperature(10)

temp_deck_1.wait_for_temp()
temp_deck_2.wait_for_temp()


### Addition of Adapters

for target in samples:
    m10.set_flow_rate(aspirate=100, dispense=100)
    m10.pick_up_tip() # Slow down head speed 0.5X for bead handling
    m10.move_to(BGI_adapter.bottom())
    m10.mix(3, 5, BGI_adapter.bottom(4))
예제 #15
0
## Sample Setup
sample_number = 96
col_num = sample_number // 8 + (1 if sample_number % 8 > 0 else 0)
samples = [col for col in temp_plate.cols()[:col_num]]

## Volume setup
ER_vol = 5.85
#Lig_vol = 8
#Fill_vol = 10
MM_dist_ER = ER_vol * col_num
#MM_dist_Lig = Lig_vol * col_num
#MM_dist_Fill = Fill_vol * col_num
"""
Blund end repair
"""
robot.comment("Yay! \ Blund-end Repair begins.")

temp_deck_1.set_temperature(10)
temp_deck_2.set_temperature(10)

temp_deck_1.wait_for_temp()
temp_deck_2.wait_for_temp()

### Addition of End repair mastermix to enzymes

m300.set_flow_rate(aspirate=180, dispense=180)
m300.pick_up_tip()  # Slow down head speed 0.5X for bead handling
m300.move_to(ER_mastermix.bottom())
m300.mix(3, 50, ER_mastermix.bottom(4))
max_speed_per_axis = {
    'x': (300),
#########################################################################################
# COMPETENT CELLS

if not robot.is_simulating():  # If the OT2 is currently not heating something
    tempdeck.set_temperature(
        TargetTemp["temp"]
    )  # Sets the temperature to the value in the TargetTemp dictionary with key temp
    tempdeck.wait_for_temp(
    )  # Pauses the protocol until the temperature deck reaches the desired temperature

target1 = Compcells1(
    Even_wells)  # Assigns the wells of Compcells1 as the target1 variable

robot.home()  # Returns the OT2 to the starting position
robot.comment(
    "Make sure that centrifuge has been chilled down to 4*C and all buffers are on ice."
)  # Produces a message on the OT2 display to inform the user of what the next step is
robot.comment(
    "All plates should be chilled at the beginning and culture should be incubated on ice for 15 minutes before start."
)  # Produces a comment on the OT2 providing information for the next step
robot.comment(
    "Once at set temperature, insert culture into slot 6 and plate onto TempDeck, then resume!"
)  # Produces a comment providing guidance to the user
robot.pause()  # Pauses the OT2 until the user resumes the process via the app

# bacterial culture								       # This is the first step of protocol, 200 uL bacterial culture at OD 0.4-0.6
for i in range(
        1
):  # Added to 96 well plate in specified wells, Range 1 means the loop runs once. Why is this a loop????
    P300.pick_up_tip()  # Forces the OT2 to equip a new pipette tip to the P300
    P300.transfer(  # Transfers reagents from a well to destination wells
예제 #17
0
import sys
sys.path.append('/root/ot2-covid19-master/ot2/library')

from constants import IP
from general.rename_robot import rename
from general.configure_static_ip import set_static_ip
from opentrons import robot

if not robot.is_simulating():
    rename('sbr1')
    set_static_ip(IP.replace('x', '54'))

robot.comment("Please, reboot")
from opentrons import labware, instruments, modules, robot

if '4ti0131_trough-12' not in labware.list():
    custom_plate = labware.create('4ti0131_trough-12',
                                  grid=(12, 1),
                                  spacing=(9, 0),
                                  diameter=8.25,
                                  depth=39.22,
                                  volume=21000)
    robot.comment('4ti0131_trough-12 added to labware database')
else:
    robot.comment(
        '4ti0131_trough-12 already exists in the OT2 database and has not been updated. Refer to Opentrons API and Custom_labware.csv'
    )

if '4ti0136_96_deep-well' not in labware.list():
    custom_plate = labware.create('4ti0136_96_deep-well',
                                  grid=(12, 8),
                                  spacing=(9, 9),
                                  diameter=8.2,
                                  depth=39.15,
                                  volume=2200)
    robot.comment('4ti0136_96_deep-well added to labware database')
else:
    robot.comment(
        '4ti0136_96_deep-well already exists in the OT2 database and has not been updated. Refer to Opentrons API and Custom_labware.csv'
    )

if 'Nunc_Omnitray' not in labware.list():
    custom_plate = labware.create('Nunc_Omnitray',
                                  grid=(12, 8),
예제 #19
0
def dispatch_commands(protocol_data, loaded_pipettes,
                      loaded_labware):  # noqa: C901 E501
    subprocedures = [
        p.get('subprocedure', []) for p in protocol_data.get('procedure', [])
    ]

    default_values = protocol_data.get('default-values', {})
    flat_subs = chain.from_iterable(subprocedures)

    for command_item in flat_subs:
        command_type = command_item.get('command')
        params = command_item.get('params', {})

        pipette = _get_pipette(params, loaded_pipettes)
        protocol_pipette_data = protocol_data\
            .get('pipettes', {})\
            .get(params.get('pipette'), {})
        pipette_name = protocol_pipette_data.get('name')

        if (not pipette_name):
            # TODO: Ian 2018-11-06 remove this fallback to 'model' when
            # backwards-compatability for JSON protocols with versioned
            # pipettes is dropped (next JSON protocol schema major bump)
            pipette_name = protocol_pipette_data.get('model')

        location = _get_location(loaded_labware, command_type, params,
                                 default_values)
        volume = params.get('volume')

        if pipette:
            # Aspirate/Dispense flow rate must be set each time for commands
            # which use pipettes right now.
            # Flow rate is persisted inside the Pipette object
            # and is settable but not easily gettable
            _set_flow_rate(pipette_name, pipette, command_type, params,
                           default_values)

        if command_type == 'delay':
            wait = params.get('wait')
            message = params.get('message')
            if wait is None:
                raise ValueError('Delay cannot be null')
            elif wait is True:
                message = message or 'Pausing until user resumes'
                robot.pause(msg=message)
            else:
                text = f'Delaying for {datetime.timedelta(seconds=wait)}'
                if message:
                    text = f"{text}. {message}"
                robot.comment(text)
                _sleep(wait)

        elif command_type == 'blowout':
            pipette.blow_out(location)

        elif command_type == 'pick-up-tip':
            pipette.pick_up_tip(location)

        elif command_type == 'drop-tip':
            pipette.drop_tip(location)

        elif command_type == 'aspirate':
            pipette.aspirate(volume, location)

        elif command_type == 'dispense':
            pipette.dispense(volume, location)

        elif command_type == 'touch-tip':
            # NOTE: if touch_tip can take a location tuple,
            # this can be much simpler
            (well_object, loc_tuple) = location

            # Use the offset baked into the well_object.
            # Do not allow API to apply its v_offset kwarg default value,
            # and do not apply the JSON protocol's default offset.
            z_from_bottom = loc_tuple[2]
            offset_from_top = (well_object.properties['depth'] -
                               z_from_bottom) * -1

            pipette.touch_tip(well_object, v_offset=offset_from_top)

        elif command_type == 'move-to-slot':
            slot = params.get('slot')
            if slot not in [str(s + 1) for s in range(12)]:
                raise ValueError(
                    '"move-to-slot" requires a valid slot, got {}'.format(
                        slot))
            x_offset = params.get('offset', {}).get('x', 0)
            y_offset = params.get('offset', {}).get('y', 0)
            z_offset = params.get('offset', {}).get('z', 0)
            slot_placeable = robot.deck[slot]
            slot_offset = (x_offset, y_offset, z_offset)

            strategy = 'direct' if params.get('force-direct') else None

            # NOTE: Robot.move_to subtracts the offset from Slot.top()[1],
            # so in order not to translate our desired offset,
            # we have to compensate by adding it here :/
            pipette.move_to((slot_placeable,
                             add(slot_offset, tuple(slot_placeable.top()[1]))),
                            strategy=strategy)
예제 #20
0
                            master_settings["P10_single"]["Rack"])
P10 = instruments.P10_Single(mount=master_settings["P10_single"]["Mount"],
                             tip_racks=[p10_tip_rack])
P10.start_at_tip(p10_tip_rack.well(P10_first_tip))

p300_tip_rack = labware.load("opentrons_96_tiprack_300ul",
                             master_settings["P300_multi"]["Rack"])
P300 = instruments.P300_Multi(mount=master_settings["P300_multi"]["Mount"],
                              tip_racks=[p300_tip_rack])
P300.start_at_tip(p300_tip_rack.cols(P300_tip_column))

# Main:
LB_vols = [target_vol * OD / target_OD for OD in sample_ODs]
tempdeck.set_temperature(37)
tempdeck.wait_for_temp()
robot.comment("Insert sample plate into position: " +
              master_settings["Plate"]["Position"])
robot.pause()
# Resuspend cells:
P300.pick_up_tip()
P300.mix(10, 100, sample_plate.cols(0).bottom(1))
P300.return_tip()
# Pipette LB and passage:
for i in range(len(sample_ODs)):
    P10.pick_up_tip()
    P10.mix(3, 10, hotplate.well(LB_well))  # Wet tip...
    P10.transfer(
        LB_vols[i],
        hotplate.well(LB_well),
        sample_plate(sample_destinations[i]),
        new_tip="never",
    )
예제 #21
0
def test_comment(virtual_smoothie_env):
    robot.reset()
    robot.clear_commands()
    robot.comment('hello')
    assert robot.commands() == ['hello']
예제 #22
0
s1000.distribute(Wash_2_vol, Wash_2, [well.top() for well in sample_plate.wells()], new_tip='once',  blow_out =True)
mag_deck.engage()
m300.delay(minutes=5)
m300.transfer(500, [well.bottom() for well in sample_plate.wells()], Liquid_trash, new_tip='always',  blow_out =True)

## Ethanol Wash 1
mag_deck.disengage()
s1000.distribute(EtOH_vol, Ethanol_1, [well.top() for well in sample_plate.wells()], new_tip='once',  blow_out =True)
mag_deck.engage()
m300.delay(minutes=5)
m300.transfer(500, [well.bottom() for well in sample_plate.wells()], Liquid_trash, new_tip='always',  blow_out =True)

## Ethanol Wash 2
mag_deck.disengage()
s1000.distribute(EtOH_vol, Ethanol_2, [well.top() for well in sample_plate.wells()], new_tip='once',  blow_out =True)
mag_deck.engage()
m300.delay(minutes=5)
m300.transfer(500, [well.bottom() for well in sample_plate.wells()], Liquid_trash, new_tip='always',  blow_out =True)

## Dry beads
robot.pause("Put the plate on the Temperature Module for 20 minutes at 55°C")

## Elution
mag_deck.disengage()
m300.distribute(Elution_vol, Elution_buffer, [well.bottom() for well in sample_plate.wells(), new_tip='always',  blow_out =True]
mag_deck.engage()
m300.delay(minutes=5)
m300.distribute(Elution_vol, [well.bottom() for well in sample_plate.wells(), [well.bottom() for well in elution_plate_DNA.wells(), new_tip='always',  blow_out =True]

robot.comment("Job's done")
예제 #23
0
    m300.transfer(85, col, m300.trash_container.top())

# wash plate with 80% EtOH twice
for etoh in ethanol_1:
    m300.pick_up_tip()
    m300.transfer(200,
                  etoh, [col[0].top() for col in mag_plate.cols()],
                  new_tip='never')
    m300.delay(seconds=30)
    for col in mag_plate.cols():
        if not m300.tip_attached:
            m300.pick_up_tip()
        m300.transfer(230, col, m300.trash_container.top(), new_tip='never')
        m300.drop_tip()

robot.comment("Air dry for 15 minutes. During this time, replenish all of the \
tip racks.")
m300.delay(minutes=15)
m300.reset()
m10.reset()

mag_module.disengage()

# transfer resuspension buffer
for col in mag_plate.cols():
    m300.pick_up_tip()
    m300.transfer(52.5, resuspension_buffer, col, new_tip='never')
    m300.mix(3, 30, col)
    m300.blow_out(col)
    m300.drop_tip()

m300.delay(minutes=2)
예제 #24
0
SA5 = mag_plate.wells('A5')
SA6 = mag_plate.wells('A6')
SA7 = mag_plate.wells('A7')
SA8 = mag_plate.wells('A8')
SA9 = mag_plate.wells('A9')
SA10 = mag_plate.wells('A10')
SA11 = mag_plate.wells('A11')
SA12 = mag_plate.wells('A12')

sample_vol = 60
bead_vol = 1.5*sample_vol
EtOH_vol = 160
EtOH_vol2 = 150
elution_vol = 35

robot.comment("Yay! \ Purification begins!")

### Beads addition
mag_deck.engage(height=10)
m300.delay(seconds=10)
mag_deck.engage(height=12)
m300.delay(seconds=10)
mag_deck.engage(height=13)
m300.delay(seconds=10)
mag_deck.engage(height=14)
m300.delay(seconds=10)
mag_deck.engage(height=15)
m300.delay(seconds=10)
mag_deck.engage(height=16)
m300.delay(seconds=10)
mag_deck.engage(height=17)
예제 #25
0
    tip_racks=tipracks,
    trash_container=trash,
    aspirate_speed=300,
    dispense_speed=400)

# ~~~~~~~~~~ PROTOCOL RUN ~~~~~~~~~
p300_multi_default_speed.pick_up_tip()

# Define number of sample rows, sample volume, height from the bottom of the islet wells
sampleRows = 3
sampleVol = 500
aspHeight = 3

#Step 1. Remove existing media

robot.comment("Removing existing media from samples.")

for row in range(0, sampleRows):
    p300_multi_default_speed.transfer(sampleVol,
                                      samplePlate.rows(row).bottom(aspHeight),
                                      wastePlate.rows(row),
                                      new_tip='never',
                                      blow_out=True)

robot.comment("Media removed.")

# Step 2. Wash islets


def washSamples(numWashes, volWash):
    robot.comment("Beginning " + str(numWashes) + " washes, " + str(volWash) +
NEW_SERIAL_NUMBER = "SB-R1"

from opentrons import robot
import os

robot.comment(f"Setting serial number to {NEW_SERIAL_NUMBER}.")

if not robot.is_simulating():
    with open("/var/serial", "w") as serial_number_file:
        serial_number_file.write(NEW_SERIAL_NUMBER + "\n")
    with open("/etc/machine-info", "w") as serial_number_file:
        serial_number_file.write(f"DEPLOYMENT=production\nPRETTY_HOSTNAME={NEW_SERIAL_NUMBER}\n")
    with open("/etc/hostname", "w") as serial_number_file:
        serial_number_file.write(NEW_SERIAL_NUMBER + "\n")

    os.sync()

    robot.comment("Done.")
def run_custom_protocol(
        p300_type: 'StringSelection...' = 'single',
        p300_mount: 'StringSelection...' = 'right',
        number_of_samples_to_process: int = 24
):
    # check:
    if number_of_samples_to_process > 96 or number_of_samples_to_process < 1:
        raise Exception('Invalid number of samples to process (must be between \
1 and 96).')

    num_cols = math.ceil(number_of_samples_to_process/8)
    num_300_racks = math.ceil((num_cols*6)/12)
    slots300 = [str(slot) for slot in range(5, 5+num_300_racks)]
    tips300 = [
        labware.load('opentrons_96_tiprack_300ul', slot) for slot in slots300]

    # pipettes
    if p300_type == 'multi':
        pip300 = instruments.P300_Multi(mount=p300_mount, tip_racks=tips300)
        samples300 = mag_plate.rows('A')[:num_cols]
    else:
        pip300 = instruments.P300_Single(mount=p300_mount, tip_racks=tips300)
        samples300 = mag_plate.wells()[:number_of_samples_to_process]
    pip300.set_flow_rate(aspirate=75, dispense=90)

    magdeck.engage(height=18)
    robot.comment('Incubating beads on magnet for 3 minutes.')
    pip300.delay(minutes=3)

    # remove and discard supernatant
    for s in samples300:
        pip300.pick_up_tip()
        pip300.transfer(65, s.bottom(1), liquid_waste[0], new_tip='never')
        pip300.blow_out()
        pip300.drop_tip()

    # TWB washes 3x
    count = 0
    total_twb = 96*3
    for wash in range(3):
        magdeck.disengage()

        # resuspend beads in TWB
        for i, s in enumerate(samples300):
            ind = (count*len(twb))//total_twb
            count += 1

            side = i % 2 if p300_type == 'multi' else math.floor(i/8) % 2
            angle = 0 if side == 0 else math.pi
            disp_loc = (s, s.from_center(r=0.85, h=-0.6, theta=angle))
            pip300.pick_up_tip()
            pip300.aspirate(100, twb[ind])
            pip300.move_to(s.bottom(5))
            pip300.dispense(100, disp_loc)
            pip300.mix(10, 80, disp_loc)
            pip300.drop_tip()

        magdeck.engage(height=18)

        if wash < 2:
            robot.comment('Incubating beads on magnet for 3 minutes')
            pip300.delay(minutes=3)
            # remove and discard supernatant
            for s in samples300:
                pip300.pick_up_tip()
                pip300.transfer(
                    120, s.bottom(1), liquid_waste[wash], new_tip='never')
                pip300.blow_out()
                pip300.drop_tip()

    robot.comment('Seal the plate, and keep on the magnetic module. The TWB \
remains in the wells to prevent overdrying of the beads')
SA5 = mag_plate.wells('A5')
SA6 = mag_plate.wells('A6')
SA7 = mag_plate.wells('A7')
SA8 = mag_plate.wells('A8')
SA9 = mag_plate.wells('A9')
SA10 = mag_plate.wells('A10')
SA11 = mag_plate.wells('A11')
SA12 = mag_plate.wells('A12')

sample_vol = 50
bead_vol = 1.5 * sample_vol
EtOH_vol = 160
EtOH_vol2 = 150
elution_vol = 35

robot.comment("Yay! \ Purification begins!")

### Beads addition
mag_deck.disengage()

for target in samples:
    m300.set_flow_rate(aspirate=180, dispense=180)
    m300.pick_up_tip()  # Slow down head speed 0.5X for bead handling
    m300.mix(3, 200, SPRI_beads)
    max_speed_per_axis = {
        'x': (100),
        'y': (100),
        'z': (50),
        'a': (20),
        'b': (20),
        'c': (20)
autoconnect-priority=20
interface-name=eth0
permissions=

[ethernet]
cloned-mac-address=permanent
mac-address-blacklist=

[ipv4]
dns-search=
method=manual
addresses={STATIC_IP}
"""

from opentrons import robot
import os

robot.comment(
    f"Run this protocol to permanently set the wired IP address of your OT-2 to {STATIC_IP}."
)

if not robot.is_simulating():
    with open(
            "/var/lib/NetworkManager/system-connections/support-team-wired-static-ip",
            "w") as keyfile:
        keyfile.write(keyfile_contents)
    os.sync()
    robot.comment("Done.")

robot.comment("Restart your OT-2 to apply the changes.")
            1,  # Sets the dispensing rate of the pipette, set this to 0.5 if using a viscous fluid
            new_tip='never'
        )  # With this option declared the Opentron will not pick up a new pipette until explicitly instructed
        P300.touch_tip(
            well_buffers96(y)
        )  # With this option declared the pipette tip will be touched to the top of the wells after pipetting
        P300.blow_out(
            well_buffers96(y)
        )  # assigns another blow out, dispensing a gust of air after dispensing to clear the pipette tip of fluid
    if y == len(
            z
    ) - 1:  # Checks if the end of the reagent list has been reached, Python lists start at 0 so y will only ever reach 5 in a list fo 6 elements len(z) needs to have 1 subtracted
        P300.drop_tip()  # Disposes of the tip on the P300
        P10.drop_tip()  # Disposes of the tip on the P10


robot.home()  # Returns the Opentron pipette to the starting location
source = 0  # Source is declared as an empty variable so it can track reagent position from the sort() function

[
    [
        sort(values, well_counter, reagent, counter)
        for well_counter, values in enumerate(reagent)
    ] for counter, reagent in enumerate(reagents1, 0)
]  # Unless you change the name of reagents1, you will never need to alter this line
# The line above executes the entire protocol, iterating through the reagent lists and destinations, as such it shouldn't need to be adjusted unless the reagent list names change

robot.comment(
    "Protocol finished"
)  # Informs the user that the protocol is complete via comment on the Opentrons