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)
Example #2
0
def run(protocol: protocol_api.ProtocolContext):
    #Labware
    #Modules
    #Plates
    #Starlab = magneto.load_labware("usascientific_96_wellplate_2.4ml_deep", label = "Deep well") # E2896-1810 11.4mm
    Eppendorf = protocol.load_labware("eppendorf_96_deepwell_2ml",
                                      6,
                                      label="Deep well")  # 11.8 mm
    #Zymo = magneto.load_labware("zymoresearch_96_deepwell_2400ul", label = "Deep well") # 12.5mm

    #Mackerey Nagel 10mm
    tiprack2 = protocol.load_labware("opentrons_96_tiprack_300ul", 2)
    #Pippetes
    p300 = protocol.load_instrument("p300_multi_gen2",
                                    "left",
                                    tip_racks=[tiprack2])

    #variables
    Height1 = 12.7
    Height2 = 13
    Height3 = 13.3
    #Commands

    protocol.delay(minutes=20)

    p300.transfer(500, Eppendorf["A1"], Eppendorf["A2"])
Example #3
0
def run(protocol: protocol_api.ProtocolContext):

    # LABWARE
    # epp_rack = protocol.load_labware('opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap', '5')
    tiprack300 = protocol.load_labware('opentrons_96_filtertiprack_200ul', '8')
    # tiprack20 = protocol.load_labware('opentrons_96_filtertiprack_20ul', '9')
    # tempdeck = protocol.load_module('tempdeck', '10') # leaving on so I don't have to move off
    # plate = protocol.load_labware('corning_96_wellplate_360ul_flat', '3')
    # reagent_rack = protocol.load_labware('opentrons_6_tuberack_nest_50ml_conical', '6')
    # lurb_rack= protocol.load_labware('opentrons_15_tuberack_nest_15ml_conical', '2')
    lurb_rack = protocol.load_labware('eppendorf5ml_15_tuberack_5000ul', '2')
    # x3_rack= protocol.load_labware('opentrons_15_tuberack_nest_15ml_conical', '6')

    # PIPETTES
    p300 = protocol.load_instrument('p300_single_gen2',
                                    'left',
                                    tip_racks=[tiprack300])

    # REAGENTS
    # x3 = x3_rack['A1'] # detergent e.g. Ultralyse 7, Ultralyse X3; 8085.11ul
    lurbOne = lurb_rack['A1']  # lurb 1; 15mL tube

    ### COMMANDS ######
    p300.pick_up_tip()
    p300.move_to(lurbOne.top())
    protocol.delay(seconds=5)
    p300.move_to(lurbOne.top(-5))
    protocol.delay(seconds=5)
    p300.move_to(lurbOne.top(-10))
    protocol.delay(seconds=5)
    p300.move_to(lurbOne.bottom(10))
    protocol.delay(seconds=5)
    p300.move_to(lurbOne.bottom(1))
    protocol.delay(seconds=5)
Example #4
0
def run(protocol: protocol_api.ProtocolContext):
    # labware
    trough = protocol.load_labware('axygen_12_reservior_22ml', '8')
    tip300_1 = protocol.load_labware('opentrons_96_tiprack_300ul', '7')
    tip300_2 = protocol.load_labware('opentrons_96_tiprack_300ul', '10')

    plate24_1A = protocol.load_labware('nunc_24_plate', '1')
    plate24_2A = protocol.load_labware('nunc_24_plate', '2')
    plate24_3A = protocol.load_labware('nunc_24_plate', '4')
    plate24_4A = protocol.load_labware('nunc_24_plate', '5')

    # pipettes
    p300m = protocol.load_instrument('p300_multi',
                                     mount='right',
                                     tip_racks=[tip300_1, tip300_2])
    p300m.flow_rate.aspirate = 200
    p300m.well_bottom_clearance.aspirate = 2
    p300m.well_bottom_clearance.dispense = 2

    #Step 1: Create list of trough wells and plate names:
    list_plate1 = [(11, plate24_1A), (10, plate24_2A), (9, plate24_3A),
                   (8, plate24_4A)]  # Defines plates to be seeded
    # Creates function to seed plates. Variables: x = seed volume, col = start trough column for set of 4 plates, 24platelist = set of plates to use.
    for (col, plate24_1), j in product(list_plate1, range(6)):
        p300m.pick_up_tip()
        for i in range(3):
            p300m.aspirate(20, trough.wells()[col].top())
            p300m.aspirate(210, trough.wells()[col])
            p300m.move_to(trough.wells()[col].top(-20))
            protocol.delay(seconds=1.0)
            p300m.dispense(220, plate24_1.wells()[4 * j].top())
            protocol.delay(seconds=1.0)
            p300m.blow_out(plate24_1.wells()[4 * j].top())
        p300m.drop_tip()
Example #5
0
def run(protocol: protocol_api.ProtocolContext):

    temp_module = protocol.load_module('Temperature Module', 5)

    p10rack = protocol.load_labware('opentrons_96_tiprack_10ul', 9)

    reagents = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap', 8)
    prep_plate = temp_module.load_labware('nest_96_wellplate_200ul_flat')

    # Using 10ul pipette for precision
    p10 = protocol.load_instrument('p10_single', 'left', tip_racks=[p10rack])

    base_recipe = {  # reagent name: [postion on tuberack, uls to each sample]
        '10X_NEBuffer_21': ['A1', 2],
        'LbCas12a': ['B1', 1],
        'reporter': ['C1', 1],  #TODO Need correct volume
        'water': ['D1', 15.75]
    }
    gRNA_uls_to_pipette = 1.25
    gRNA_recipe = {  # reagent name: [postion on tuberack, uls to each sample]
        'N-gene_gRNA': ['A2', gRNA_uls_to_pipette],
        'E-gene_gRNA': ['B2', gRNA_uls_to_pipette],
        'RNase_P_gRNA': ['C2', gRNA_uls_to_pipette]
    }

    prep_plate_wells = ['A1', 'A2',
                        'A3']  #1st: N-gene wells, 2nd: E-gene, 3rd: RNase P
    prep_plate_locations = [
        prep_plate.wells(well) for well in prep_plate_wells
    ]

    reporter_recipe = base_recipe['reporter']  #move reporter to be used later

    #    print(prep_plate_locations)
    #Begin Procedure ---------------------------------------------------------
    for reagent in base_recipe:  #TODO Don't need for-loop, can do with .distribute only
        p10.distribute(
            base_recipe[reagent][1],  #volume
            reagents.wells(base_recipe[reagent][0]),  #source location
            prep_plate_locations)  #dest location

    for group, gRNA in enumerate(gRNA_recipe):
        p10.transfer(
            gRNA_recipe[gRNA][1],  #volume
            reagents.wells(gRNA_recipe[gRNA][0]),  #source location
            prep_plate_locations[group],  #dest location
            mix_after=(2, 10))  #ensure good mixing

    temp_module.set_temperature(37)  #robot pauses until temperature is reached
    protocol.delay(minutes=30)

    temp_module.set_temperature(4)
def wash_beads(
    protocol: protocol_api.ProtocolContext,
    source_plate: Labware = None,
    volume_ul: int = 0,
):
    """
    Perform a Bead Wash.

    Args:
        protocol: The protocol context to operate on.
        source_plate: The plate to perform the wash on.
        volume_ul: What volume of liquid to use for the wash, in uL.

    """
    mag_deck = protocol.loaded_modules[MAG_DECK["SLOT"]]
    p300 = protocol.loaded_instruments[P300_MULTI["POSITION"]]
    reaction_plate = protocol.loaded_labwares[MAG_DECK["SLOT"]]
    waste_reservior = protocol.loaded_labwares[WASTE_RESERVOIR["SLOT"]]
    num_cols = len(reaction_plate.columns())

    # 2. Remove the plate from the magnetic stand
    mag_deck.disengage()

    wash(
        num_cols=num_cols,
        pipette=p300,
        source_plate=source_plate,
        destination_plate=reaction_plate.columns(),
        volume_ul=volume_ul,
    )

    # 3. Reseal the plate, then shake at 1,050 rpm for 1 minute.
    # Step 3 happen outside of OT-2.
    protocol.pause()

    # 4. Place the plate back on the magnetic stand for 2 minutes, or until all the beads have collected.
    mag_deck.engage(height=MAGDECK_ENGAGE_HEIGHT)
    protocol.delay(minutes=2)

    # 5. Keeping the plate on the magnet, discard the supernatant from each well.
    # IMPORTANT! Avoid disturbing the beads.
    discard_supernatant(
        num_cols=num_cols,
        pipette=p300,
        source_plate=reaction_plate.columns(),
        destination_plate=waste_reservior.columns(),
    )
Example #7
0
def run(protocol: protocol_api.ProtocolContext):
    #load tip rack, pipette and labware
    tip_rack = protocol.load_labware('opentrons_96_tiprack_300ul', 2)

    pipette_right = protocol.load_instrument('p300_single',
                                             'right',
                                             tip_racks=[tip_rack])

    #load bioshake - remember to change serial number to match your devices!
    device = QIDevice(serial_number='19762',
                      deck_position=1,
                      adapter_set_up=1,
                      protocol=protocol)

    #first, upload Qinstrument's custom labware to the OT-2. Next, make sure you
    #add the z_offset, item_depth, and item_volume
    lbw = device.load_labware('2016_1062',
                              z_offset=(11, 5),
                              item_depth=(37.5, 30),
                              item_volume=(1500, 500))
    #resetting bioshake just in case
    device.exec_cmd('resetDevice')

    #teseting pipette
    pipette_right.pick_up_tip()
    pipette_right.aspirate(100, lbw['AA1'])
    pipette_right.dispense(100, lbw['AA5'])
    pipette_right.drop_tip()

    #testing temp at 37C for 20 seconds while shaking still occurs
    device.exec_cmd('setShakeTargetSpeed500')
    device.exec_cmd('shakeOn')
    device.exec_cmd('setTempTarget370', blocking=True)
    device.exec_cmd('tempOn', polling=True)
    protocol.delay(seconds=20,
                   msg='shaking at 500rpm and heating at 37C for 20 seconds')
    device.exec_cmd('shakeOff')

    #testing pipette with temperature on
    pipette_right.pick_up_tip()
    pipette_right.aspirate(100, lbw['AA2'])
    pipette_right.dispense(100, lbw['AA3'])
    pipette_right.drop_tip()

    device.exec_cmd('tempOff')

    protocol.comment('Protocol complete.')
def run(protocol: protocol_api.ProtocolContext):

    # LABWARE
    fuge_rack = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap', '11')
    tiprack20 = protocol.load_labware('opentrons_96_filtertiprack_20ul', '9')
    tempdeck = protocol.load_module('tempdeck', '10')
    pcr_plate = tempdeck.load_labware('abi_96_wellplate_250ul')
    ww_plate1 = protocol.load_labware('bioer_96_wellplate_2200ul', '1')
    ww_plate2 = protocol.load_labware('bioer_96_wellplate_2200ul', '5')

    # PIPETTES
    p20 = protocol.load_instrument('p20_single_gen2',
                                   'right',
                                   tip_racks=[tiprack20])

    # REAGENTS
    LU_Mix = fuge_rack['A1']  # LU MasterMix

    # LISTS
    rows = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
    tot_ww_plates = [ww_plate1, ww_plate2]

    # #### COMMANDS ######
    # aspirate mmix to all wells in 96w plate; 15*96 = 1440ul*1.1=1584
    h_list = tip_heightsEpp(1584, 96, 15)
    well_num = 1
    p20.pick_up_tip()
    for row in rows:  #8 rows
        for col in range(1, 13):  #12 cols
            dest = row + str(col)
            p20.aspirate(15, LU_Mix.bottom(h_list[well_num - 1]), rate=0.75)
            protocol.delay(seconds=1)  #head vol for more accurate pipetting
            p20.move_to(LU_Mix.bottom(38))
            protocol.delay(seconds=1)  #equilibrate
            p20.touch_tip(v_offset=-4)
            p20.dispense(15, pcr_plate[dest].bottom(1))
            p20.blow_out(pcr_plate[dest].bottom(8))
            p20.touch_tip()
            well_num += 1
    p20.drop_tip()

    for x, ww_plate in enumerate(tot_ww_plates):
        for col in range(0, 2):
            for row in rows:
                p20.pick_up_tip()
                source = row + str(6 * col + 5)  #A5, B5, C5
                dest1 = row + str(6 * x + 3 * col + 1)  #A1, #A2, #A3
                dest2 = row + str(6 * x + 3 * col + 2)
                dest3 = row + str(6 * x + 3 * col + 3)
                p20.aspirate(18, ww_plate[source].bottom(1), rate=0.75)
                protocol.delay(seconds=2)  #equilibrate
                p20.touch_tip()
                p20.dispense(5, pcr_plate[dest1].bottom(1))
                p20.touch_tip()
                p20.dispense(5, pcr_plate[dest2].bottom(1))
                p20.touch_tip()
                p20.dispense(5, pcr_plate[dest3].bottom(1))
                p20.touch_tip()
                p20.drop_tip()
def run(protocol: protocol_api.ProtocolContext):

    # LABWARE
    tiprack300 = protocol.load_labware('opentrons_96_filtertiprack_200ul', '8')
    tiprack20 = protocol.load_labware('opentrons_96_filtertiprack_20ul', '9')
    # tempdeck = protocol.load_module('tempdeck', '4')
    # plate = tempdeck.load_labware('opentrons_96_aluminumblock_generic_pcr_strip_200ul')
    # plate = tempdeck.load_labware('abi_96_wellplate_250ul')
    sectempdeck = protocol.load_module('tempdeck', '10')
    fuge_rack = sectempdeck.load_labware(
        'opentrons_24_aluminumblock_generic_2ml_screwcap')
    holder_1 = protocol.load_labware(
        '8wstriptubesonfilterracks_96_aluminumblock_250ul', '3')
    holder_2 = protocol.load_labware(
        '8wstriptubesonfilterracks_96_aluminumblock_250ul', '6')
    # PIPETTES
    p300 = protocol.load_instrument('p300_single_gen2',
                                    'left',
                                    tip_racks=[tiprack300])
    p20 = protocol.load_instrument('p20_single_gen2',
                                   'right',
                                   tip_racks=[tiprack20])

    # REAGENTS
    SAMP_1mix = fuge_rack['B5']
    SAMP_2mix = fuge_rack['D1']
    SAMP_3mix = fuge_rack['D2']
    SAMP_4mix = fuge_rack['D3']
    SAMP_5mix = fuge_rack['B6']
    SAMP_6mix = fuge_rack['C1']
    SAMP_7mix = fuge_rack['C2']
    SAMP_8mix = fuge_rack['C3']

    # user inputs
    # num_of_sample_reps is another way of stating number of strips
    num_of_sample_reps = 6

    holderList = [holder_1]
    # lists
    # ALL_SAMPs = [samp_1, samp_2, samp_3, samp_4, samp_5, samp_6, samp_7, WATER]
    SAMP_mixes = [
        SAMP_1mix, SAMP_2mix, SAMP_3mix, SAMP_4mix, SAMP_5mix, SAMP_6mix,
        SAMP_7mix, SAMP_8mix
    ]
    # SAMP_mixes = [SAMP_1mix, SAMP_2mix, SAMP_3mix, SAMP_4mix, SAMP_5mix, SAMP_6mix, SAMP_7mix, WATER]
    SAMP_wells = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']

    # #### COMMANDS ######
    # Add sample DNA, mix, distribute to strip tubes
    for i, mixtube in enumerate(SAMP_mixes):
        for y in range(0, len(holderList)):
            p300.pick_up_tip()
            p300.move_to(mixtube.bottom(40))
            p300.aspirate(num_of_sample_reps * 20 * 1.08,
                          mixtube.bottom(2))  # 6*20*1.08 = 130
            protocol.delay(seconds=1)  #equilibrate
            p300.touch_tip(v_offset=-3)
            holderPos = y
            holder = holderList[holderPos]
            start = 6 * y
            stop = num_of_sample_reps if num_of_sample_reps <= 6 * y + 6 else 6 * y + 6  # This is max it can go in cycle; can't go above e.g. A13 !<>
            for x in range(start,
                           stop):  # samples in 1-6, 7-12, 13-18 increments
                # print ("start: ", start, "stop: ", stop)
                row = SAMP_wells[i]
                dest = row + str(
                    2 * x + 1 - 12 * holderPos)  # need +1 offset for col
                p300.move_to(
                    holder[dest].bottom(40))  #move across holder in +4cm pos
                p300.dispense(
                    20, holder[dest].bottom(6),
                    rate=0.75)  # more height so tip doesn't touch pellet
                # p300.move_to(holder[dest].bottom(8))
                # p300.blow_out(holder[dest]. bottom(8))
                p300.touch_tip()
                p300.move_to(holder[dest].top(
                ))  # centers tip so tip doesn't lift tubes after touch
                p300.move_to(
                    holder[dest].bottom(40))  #move across holder in +4cm pos
                # p300.move_to(holder[dest].bottom(40)) #move back holder in +4cm pos
                # p300.move_to(mixtube.bottom(40)) #return to tube at +4cm so no crash into lyo tubes
            p300.drop_tip()
Example #10
0
def run(protocol: protocol_api.ProtocolContext):

    # LABWARE
    fuge_rack = protocol.load_labware('vwr_24_tuberack_1500ul', '1')
    stds_rack = protocol.load_labware('vwr_24_tuberack_1500ul', '2')
    tiprack300 = protocol.load_labware('opentrons_96_filtertiprack_200ul', '8')
    tiprack20 = protocol.load_labware('opentrons_96_filtertiprack_20ul', '9')
    tempdeck = protocol.load_module('tempdeck', '10')
    # plate = tempdeck.load_labware('amplifyt_96_aluminumblock_300ul')
    plate = tempdeck.load_labware('abi_96_wellplate_250ul')
    # PIPETTES
    p300 = protocol.load_instrument('p300_single_gen2',
                                    'left',
                                    tip_racks=[tiprack300])
    p20 = protocol.load_instrument('p20_single_gen2',
                                   'right',
                                   tip_racks=[tiprack20])

    # REAGENTS
    # sds_rack
    sN_mix = stds_rack['D1']  # empty; receives BPW_mix and water for stds
    std_1 = stds_rack['A3']  # 990ul Water
    std_2 = stds_rack['A4']  # 900ul water
    std_3 = stds_rack['A5']  # 900ul water
    std_4 = stds_rack['A6']  # 900ul water
    std_5 = stds_rack['B3']  # 900ul water
    std_6 = stds_rack['B4']  # 900ul water
    std_7 = stds_rack['B5']  # 900ul water
    water = stds_rack['B6']  # 1000ul water
    std_1mix = stds_rack['C3']  # empty
    std_2mix = stds_rack['C4']  # empty
    std_3mix = stds_rack['C5']  # empty
    std_4mix = stds_rack['C6']  # empty
    std_5mix = stds_rack['D3']  # empty
    std_6mix = stds_rack['D4']  # empty
    std_7mix = stds_rack['D5']  # empty
    NTC_mix = stds_rack['D6']  # empty, receives sN_mix and water as NTC

    #fuge_rack
    # bpwd_mix = fuge_rack['A1'] #empty
    # liquid_trash = fuge_rack['B1']
    MIX_bw = fuge_rack['D1']  # see sheet, but gen around 1705 ul; use 2mL tube
    probe_10uM = fuge_rack['C1']
    fwd_10uM = fuge_rack['C2']  # min 300ul
    rev_10uM = fuge_rack['D2']  # min 300ul
    tube_upp = fuge_rack['A4']  # e.g. 0.625uM # empty
    tube_mid = fuge_rack['A5']  # e.g. 1.25uM # empty
    tube_low = fuge_rack['A6']  # e.g. 2.5uM # empty

    probe_mix_1 = fuge_rack['C4']  # e.g. 0.625uM # empty
    probe_mix_2 = fuge_rack['C5']  # e.g. 1.25uM # empty
    probe_mix_3 = fuge_rack['C6']  # e.g. 2.5uM # empty
    probe_mix_4 = fuge_rack['D4']  # e.g. 5.0uM # empty
    probe_mix_5 = fuge_rack['D5']  # e.g. 7.5uM # empty
    probe_mix_6 = fuge_rack['D6']  # e.g. 10uM # empty

    # user inputs
    p300_max_vol = 200
    orig_F_conc = 10  # What is the starting F primer concentration? (in uM)
    orig_R_conc = 10  # What is the starting R primer concentration? (in uM)
    orig_P_conc = 10  # What is probe starting concentration? (in uM)
    P_conc = 300  # What is the probe concentration for the stds?
    P_50 = 50  # Probe at lowest conc.
    P_100 = 100  # Probe at conc
    P_200 = 200  # Probe at conc
    P_400 = 400  # Probe at conc
    P_600 = 600  # Probe at conc
    P_800 = 800  # Probe at highest conc.
    sample_reps = 24  # How many samples at each F, R conc will be run?
    tot_stds = 21  # How many wells of standards will be run? (in # wells)
    tot_NTCs = 3  # How many wells of NTCs will be run? (in # wells)
    tot_samp = 72  # How many samples with varying conditions will be run? (in # wells)
    rxn_base = 8.86  # Everything in PCR buffer (Mg2+, dNTPs, polymerase, enhancers, stabilizers, sugars, etc.). (in uL)
    rxn_base_plus_water = 14.8  # This value set from other experiments.
    tot_rxn_vol = 20  # What is total volume of PCR reaction in plate/tube? (in ul)
    F_upp = 500  # F primer at highest concentration. (in nM)
    F_mid = 400  # What is the constant F primer concentration for standards? This should be guess or from literature or empirically determined. (in nM)
    F_low = 300  # F primer at concentration. (in nM)
    R_upp = 500  # R primer at lowest concentration. (in nM)
    R_mid = 400  # What is the constant R primer concentration for standards? This should be guess or from literature or empirically determined. (in nM)
    R_low = 300  # R primer at concentration. (in nM)
    dna_per_rxn = 2  # How much standard, positive control or NTC to add per well.
    std_NTC_reps = 3  # How many standard and NTC replicates? (int)
    P_reps = 12  # How many wells will use probe primer at particular concentration? (int)
    P_vol_rxn = 1.6  # What vol of probe will be added to reaction? (in ul)
    P_int_vol = 50  # What is the volume of F intermediate primer in new tube? (in ul)
    percent_waste = 0.2  # What percentage waste? (decimal)
    sN_mix_waste_offset = 0.05  # How much percent_waste offset should sN_mix use? This calculated as percent_waste-sN_mix_overage = percent_waste for sN_mix_overage e.g. (20-7=13%) Should not be 0 otherwise offset = percent_waste. (decimal)
    samp_int_mix_waste_offset = 0.05  # How much percent_waste offset should R_mix use? This calculated as percent_waste-R_mix_overage = percent_waste for R_mix_overage e.g. (20-=13%) If 0, then offset = percent_waste. (decimal)
    std_NTC_waste_offset = 0.07  # How much percent_waste offset should std_NTC use? (decimal)
    mix_samp_XFR_well_waste_offset = 0.08  #How much should offset be from each sample tube, upper, mid, low to the plate wells? Will receive P, be mixed and then aliquoted to 3 wells.

    # calcs
    tot_rxns = tot_stds + tot_NTCs + tot_samp  # Calc what is total # rxns. (int)
    tot_stds_NTC = tot_stds + tot_NTCs  # Calc number of standards and nontemplate controls. (int)
    rxn_vol_no_dna = tot_rxn_vol - dna_per_rxn  # Calc what is volume of PCR rxn with no DNA added. (in ul)
    mix_bw_tot = rxn_base_plus_water * tot_rxns * (
        1 + percent_waste)  # Tube with mix containing base and water.
    mix_bw_XFR_mix_sn = rxn_base_plus_water * tot_stds_NTC * (
        1 + percent_waste - sN_mix_waste_offset
    )  # Transfer this amount from MIX_bw to new tube to receive F, R, P for std and NTC prep
    std_vol_F_per_rxn = F_low / 1000 * tot_rxn_vol / orig_F_conc  # Calc adding this much F primer to each std rxn
    std_vol_R_per_rxn = R_low / 1000 * tot_rxn_vol / orig_R_conc  # Calc adding this much R primer to each std rxn
    std_vol_P_per_rxn = P_conc / 1000 * tot_rxn_vol / orig_P_conc  # Calc adding this much Probe to each std rxn
    std_vol_water_per_rxn = 18 - (
        rxn_base_plus_water + std_vol_F_per_rxn + std_vol_R_per_rxn +
        std_vol_P_per_rxn
    )  # How much water is added to the std_ntc reactions. Should be 18ul to receive 2ul DNA. (in ul)
    std_vol_F_mix = std_vol_F_per_rxn * tot_stds_NTC * (
        1 + percent_waste - sN_mix_waste_offset
    )  # How much F primer to add to MIX_sn?
    std_vol_R_mix = std_vol_R_per_rxn * tot_stds_NTC * (
        1 + percent_waste - sN_mix_waste_offset
    )  # How much R primer to add to MIX_sn?
    std_vol_P_mix = std_vol_P_per_rxn * tot_stds_NTC * (
        1 + percent_waste - sN_mix_waste_offset
    )  # How much P primer to add to MIX_sn?
    std_vol_water_mix = std_vol_water_per_rxn * tot_stds_NTC * (
        1 + percent_waste - sN_mix_waste_offset
    )  # How much water  to add to MIX_sn?
    mix_sn_tot = mix_bw_XFR_mix_sn + std_vol_F_mix + std_vol_R_mix + std_vol_P_mix + std_vol_water_mix  # Mix containing base+water+F,R,P. Needs to be aliquoted to std_int tubes
    mix_sn_XFR_to_std_int = std_NTC_reps * rxn_vol_no_dna * (
        1 + percent_waste - std_NTC_waste_offset
    )  # transfer this amount to std_int tubes
    std_dna_XFR_to_std_int = 6.72  #transfer this amount DNA to std_int_tubes to mix and aliquot to 3 wells
    dna_10x_dna_per_rxn = dna_per_rxn / 10  # Dilute DNA vol added by 10x and use std_4 instead of std_5 to save vol for P and F, R at upp
    mix_bw_XFR_samp_int = sample_reps * rxn_base_plus_water * (
        1 + percent_waste - samp_int_mix_waste_offset
    )  # transfer this amount from mix_bw to a new sample intermediate tube for diff values of F, R conc. Need to add 2ul from DNA
    dna_XFR_samp_int = sample_reps * dna_10x_dna_per_rxn * (
        1 + percent_waste - samp_int_mix_waste_offset
    )  # Add this DNA to a tube and mix before aliquoting to samp_int
    F_mid_rxn = F_mid / 1000 * tot_rxn_vol / orig_F_conc  # How much F @ mid conc to add to rxn.
    F_mid_mix = F_mid_rxn * sample_reps * (
        1 + percent_waste - samp_int_mix_waste_offset
    )  # How much F to add to mix
    R_mid_rxn = R_mid / 1000 * tot_rxn_vol / orig_R_conc  # How much R @ mid conc to add to rxn.
    R_mid_mix = R_mid_rxn * sample_reps * (
        1 + percent_waste - samp_int_mix_waste_offset
    )  # How much R to add to mix
    F_low_rxn = F_low / 1000 * tot_rxn_vol / orig_F_conc  # How much F @ low conc to add to rxn.
    F_low_mix = F_low_rxn * sample_reps * (
        1 + percent_waste - samp_int_mix_waste_offset
    )  # How much F to add to mix
    R_low_rxn = R_low / 1000 * tot_rxn_vol / orig_R_conc  # How much R @ low conc to add to rxn.
    R_low_mix = R_low_rxn * sample_reps * (
        1 + percent_waste - samp_int_mix_waste_offset
    )  # How much R to add to mix
    F_upp_rxn = F_upp / 1000 * tot_rxn_vol / orig_F_conc  # How much F @ upp conc to add to rxn.
    F_upp_mix = F_upp_rxn * sample_reps * (
        1 + percent_waste - samp_int_mix_waste_offset
    )  # How much F to add to mix
    R_upp_rxn = R_upp / 1000 * tot_rxn_vol / orig_R_conc  # How much R @ upp conc to add to rxn.
    R_upp_mix = R_upp_rxn * sample_reps * (
        1 + percent_waste - samp_int_mix_waste_offset
    )  # How much R to add to mix
    water_upp_rxn = tot_rxn_vol - (rxn_base_plus_water + dna_10x_dna_per_rxn +
                                   F_upp_rxn + R_upp_rxn + P_vol_rxn
                                   )  # How much water to add to upp rxn
    water_upp_mix = water_upp_rxn * sample_reps * (
        1 + percent_waste - samp_int_mix_waste_offset
    )  # How much water to add to upp mix
    water_low_rxn = 20 - (dna_10x_dna_per_rxn + F_low_rxn + R_low_rxn +
                          rxn_base_plus_water + P_vol_rxn
                          )  # How much water to add to low rxn
    water_low_mix = water_low_rxn * sample_reps * (
        1 + percent_waste - samp_int_mix_waste_offset
    )  # How much water to add to low mix
    water_mid_rxn = 20 - (rxn_base_plus_water + P_vol_rxn +
                          dna_10x_dna_per_rxn + F_mid_rxn + R_mid_rxn
                          )  # how much water to add to mid rxn
    water_mid_mix = water_mid_rxn * sample_reps * (
        1 + percent_waste - samp_int_mix_waste_offset
    )  # how much water to add to mid mix
    MIX_upp_samp_int = mix_bw_XFR_samp_int + dna_XFR_samp_int + F_upp_mix + R_upp_mix + water_upp_mix  # How much in upper intermediate sample tube?
    MIX_mid_samp_int = mix_bw_XFR_samp_int + dna_XFR_samp_int + F_mid_mix + R_mid_mix + water_mid_mix  # How much in middle intermediate sample tube?
    MIX_low_samp_int = mix_bw_XFR_samp_int + dna_XFR_samp_int + F_low_mix + R_low_mix + water_low_mix  # How much in lower intermediate sample tube?
    mix_samp_XFR_to_well = 82.432  # How much to add to plate wells
    P_50_int_conc = P_50 / 1000 * tot_rxn_vol / P_vol_rxn  # What intermediate (int) concentration of  Probe is needed such that by adding 1.6ul I obtain a final concentration of 50, 100, 200…etc in rxn well? (in uM)
    P_100_int_conc = P_100 / 1000 * tot_rxn_vol / P_vol_rxn  # What intermediate (int) concentration of  Probe is needed such that by adding 1.6ul I obtain a final concentration of 50, 100, 200…etc in rxn well? (in uM)
    P_200_int_conc = P_200 / 1000 * tot_rxn_vol / P_vol_rxn  # What intermediate (int) concentration of  Probe is needed such that by adding 1.6ul I obtain a final concentration of 50, 100, 200…etc in rxn well? (in uM)
    P_400_int_conc = P_400 / 1000 * tot_rxn_vol / P_vol_rxn  # What intermediate (int) concentration of  Probe is needed such that by adding 1.6ul I obtain a final concentration of 50, 100, 200…etc in rxn well? (in uM)
    P_600_int_conc = P_600 / 1000 * tot_rxn_vol / P_vol_rxn  # What intermediate (int) concentration of  Probe is needed such that by adding 1.6ul I obtain a final concentration of 50, 100, 200…etc in rxn well? (in uM)
    P_800_int_conc = P_800 / 1000 * tot_rxn_vol / P_vol_rxn  # What intermediate (int) concentration of  Probe is needed such that by adding 1.6ul I obtain a final concentration of 50, 100, 200…etc in rxn well? (in uM)
    P_50_int_primer = P_50_int_conc * P_int_vol / orig_P_conc  # What amount of primer should be added to generate int F primer conc? (in ul)
    P_100_int_primer = P_100_int_conc * P_int_vol / orig_P_conc  # What amount of water should be added to generate int F primer conc? (in ul)
    P_200_int_primer = P_200_int_conc * P_int_vol / orig_P_conc  # What amount of primer should be added to generate int F primer conc? (in ul)
    P_400_int_primer = P_400_int_conc * P_int_vol / orig_P_conc  # What amount of water should be added to generate int F primer conc? (in ul)
    P_600_int_primer = P_600_int_conc * P_int_vol / orig_P_conc  # What amount of primer should be added to generate int F primer conc? (in ul)
    P_800_int_primer = P_800_int_conc * P_int_vol / orig_P_conc  # What amount of water should be added to generate int F primer conc? (in ul)
    P_50_int_water = P_int_vol - P_50_int_primer  # What amount of primer should be added to generate int F primer conc? (in ul)
    P_100_int_water = P_int_vol - P_100_int_primer  # What amount of water should be added to generate int F primer conc? (in ul)
    P_200_int_water = P_int_vol - P_200_int_primer  # What amount of primer should be added to generate int F primer conc? (in ul)
    P_400_int_water = P_int_vol - P_400_int_primer  # What amount of water should be added to generate int F primer conc? (in ul)
    P_600_int_water = P_int_vol - P_600_int_primer  # What amount of primer should be added to generate int F primer conc? (in ul)
    P_800_int_water = P_int_vol - P_800_int_primer  # What amount of water should be added to generate int F primer conc? (in ul)
    p_int_XFR_to_well = P_vol_rxn * 4 * (
        1 + percent_waste - mix_samp_XFR_well_waste_offset
    )  # What amount of probe intermediate to add to bolus in wells?

    #checks
    print("mix_bw_tot", mix_bw_tot)
    print("mix_bw_tot", mix_sn_tot)
    print("mix_bw_XFR_samp_int", mix_bw_XFR_samp_int)
    print("MIX_upp_samp_int", MIX_upp_samp_int)
    print("MIX_low_samp_int", MIX_low_samp_int)
    print("MIX_low_samp_int", MIX_low_samp_int)
    # lists
    # plate_col = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
    F_samp_vols = [F_upp_mix, F_mid_mix, F_low_mix]
    R_samp_vols = [R_upp_mix, R_mid_mix, R_low_mix]
    plate_rows = ['A', 'B', 'C', 'D', 'E', 'F']
    # all_fwd = [fwd_1, fwd_2, fwd_3, fwd_4, fwd_5, fwd_6]
    std_tubes = [std_1, std_2, std_3, std_4, std_5, std_6, std_7, water]
    std_mixes = [
        std_1mix, std_2mix, std_3mix, std_4mix, std_5mix, std_6mix, std_7mix,
        NTC_mix
    ]
    std_wells = ['G1', 'G4', 'G7', 'G10', 'H1', 'H4', 'H7', 'H10']
    samp_tubes = [tube_upp, tube_mid, tube_low]
    probe_mixes = [
        probe_mix_1, probe_mix_2, probe_mix_3, probe_mix_4, probe_mix_5,
        probe_mix_6
    ]
    P_in_mix = [
        P_50_int_primer, P_100_int_primer, P_200_int_primer, P_400_int_primer,
        P_600_int_primer, P_800_int_primer
    ]
    W_in_mix = [
        P_50_int_water, P_100_int_water, P_200_int_water, P_400_int_water,
        P_600_int_water, P_800_int_water
    ]

    # #### COMMANDS ######

    # prepare sN_mix
    # add MIX_bw to sN_mix tube
    p300.pick_up_tip()
    p300.flow_rate.aspirate = 92.86  #default
    p300.flow_rate.dispense = 92.86  #default
    MIX_bw_heights = tip_heights(
        mix_bw_tot, len(split_asp(mix_bw_XFR_mix_sn, p300_max_vol)),
        split_asp(mix_bw_XFR_mix_sn, p300_max_vol)[0])
    p300.mix(3, 200, MIX_bw.bottom(MIX_bw_heights[0]))
    p300.flow_rate.aspirate = 40  #default
    p300.flow_rate.dispense = 40  #default
    for j in range(len(split_asp(mix_bw_XFR_mix_sn, p300_max_vol))):
        amt = split_asp(mix_bw_XFR_mix_sn, p300_max_vol)[j]
        p300.aspirate(amt, MIX_bw.bottom(MIX_bw_heights[j]))
        h = tip_heights(amt + amt * j, 1, 0)[0]
        p300.dispense(amt, sN_mix.bottom(h + 5))
        p300.blow_out(sN_mix.bottom(20))  # want to be above liquid level
        p300.touch_tip()
    p300.drop_tip()
    # transfer water to sN__mix
    p300.flow_rate.aspirate = 40  #default
    p300.flow_rate.dispense = 40  #default
    p300.transfer(
        std_vol_water_mix,  # 27.6ul
        water.bottom(20),
        sN_mix.bottom(tip_heights(mix_bw_XFR_mix_sn, 1, 0)[0]),
        blow_out=True,
        blowout_location='destination well')
    # transfer F primer @ std conditions to sN__mix
    p300.transfer(
        std_vol_F_mix,  #22.08ul
        fwd_10uM.bottom(3),
        sN_mix.bottom(tip_heights(mix_bw_XFR_mix_sn, 1, 0)[0]),
        blow_out=True,
        mix_after=(2, 30),
        blowout_location='destination well')
    # transfer R primer @ std conditions to sN__mix
    p300.transfer(  #some resid fluid on outside
        std_vol_R_mix,  #22.08ul
        rev_10uM.bottom(3),
        sN_mix.bottom(tip_heights(mix_bw_XFR_mix_sn, 1, 0)[0]),
        blow_out=True,
        mix_after=(2, 30),
        blowout_location='destination well')
    # transfer Probe @ std conditions to sN__mix
    p20.flow_rate.aspirate = 4
    p20.flow_rate.dispense = 4
    p20.transfer(  #some resid fluid on outside
        std_vol_P_mix,  #16.56ul
        probe_10uM.bottom(3),
        sN_mix.bottom(tip_heights(mix_bw_XFR_mix_sn, 1, 0)[0]),
        blow_out=True,
        mix_after=(2, 20),
        blowout_location='destination well')
    p300.flow_rate.aspirate = 92.86  #default
    p300.flow_rate.dispense = 92.86  #default
    p20.flow_rate.aspirate = 7.56
    p20.flow_rate.dispense = 7.56

    # transfer sN_mix to intermediate tubes (std_mixes)
    std_mix_heights = tip_heights(mix_sn_tot, len(std_mixes),
                                  mix_sn_XFR_to_std_int)  #[13,11,8,6,4,2,0]
    print(mix_bw_XFR_mix_sn)
    print(mix_sn_tot)
    print(std_mix_heights)
    p300.pick_up_tip()
    p300.mix(7, 200, sN_mix.bottom(std_mix_heights[0]))  #10mm from bottom
    p300.flow_rate.aspirate = 30
    p300.flow_rate.dispense = 40
    # p300.well_bottom_clearance.aspirate = std_mix_heights[0] #mm
    for tube, h in zip(std_mixes, std_mix_heights):
        # p300.well_bottom_clearance.aspirate = h #mm
        p300.aspirate(mix_sn_XFR_to_std_int,
                      sN_mix.bottom(h))  # 18 * 3 * 1.12-0.05= 54 + 6 =60ul
        protocol.delay(seconds=2)  #tip equilibrate
        p300.move_to(sN_mix.bottom(35))  # excess tip fluid condense
        protocol.delay(seconds=3)  #tip droplets slide
        p300.touch_tip()
        p300.dispense(mix_sn_XFR_to_std_int, tube)
    p300.drop_tip()
    p300.flow_rate.aspirate = 92.86  #reset to default
    p300.flow_rate.dispense = 92.86  #reset to default
    p300.well_bottom_clearance.aspirate = 10  #mm default

    # transfer std DNA into intermediate std_mixes tubes and then to plate
    for std, intTube, well in zip(std_tubes, std_mixes, std_wells):
        p20.pick_up_tip()
        p300.pick_up_tip()
        p20.flow_rate.aspirate = 4
        p20.flow_rate.dispense = 4
        p20.aspirate(
            std_dna_XFR_to_std_int, std
        )  #aspirate from std_1 into std_mix (intermediate tube) e.g. 6.42 ul
        protocol.delay(seconds=3)  #equilibrate
        p20.touch_tip()
        p20.dispense(std_dna_XFR_to_std_int, intTube)
        # p20.move_to(intTube.bottom(3))
        p20.flow_rate.aspirate = 7.56
        p20.flow_rate.dispense = 7.56
        p20.mix(2, 20,
                intTube.bottom(3))  #ensure vol in tip in intTube and washed
        p20.blow_out()
        p300.move_to(
            intTube.bottom(40))  #prevent tip from crashing into tube cap
        p300.mix(7, 50, intTube.bottom(1))
        protocol.delay(seconds=2)
        # p300.move_to(intTube.bottom(10)) #prevent air bubbles in mmix during blow out
        p300.blow_out(intTube.bottom(10))
        p20.move_to(intTube.bottom(40))
        p20.flow_rate.aspirate = 4
        p20.flow_rate.dispense = 4
        for x in range(0, 3):  # need int 1, 2, and 3
            p20.aspirate(20, intTube)
            protocol.delay(seconds=2)  #equilibrate
            # find digits in well, G1 and G10 and puts into list
            findNums = [int(i) for i in well.split()[0] if i.isdigit()]
            # joins nums from list [1, 0] -> 10 type = string
            colNum = ''.join(map(str, findNums))
            # this finds row
            row = well.split()[0][0]
            dest = row + str(int(colNum) + x)  # row + neighbor well i.e. 1, 2
            p20.dispense(20, plate[dest].bottom(1))
            p20.move_to(plate[dest].bottom(4))
            p20.blow_out()
            # p20.touch_tip()
        p300.drop_tip()
        p20.drop_tip()
    p20.flow_rate.aspirate = 7.56
    p20.flow_rate.dispense = 7.56
    p20.well_bottom_clearance.dispense = 1
    p20.well_bottom_clearance.aspirate = 1

    # create samp_int tube mixes. sample intermediate
    # first add DNA from a std tube e.g. std_4
    p20.transfer(
        dna_XFR_samp_int * 3,  # ~3 sets of 24 samples
        std_6.bottom(2),
        MIX_bw.bottom(tip_heights(mix_bw_tot - mix_bw_XFR_mix_sn, 1, 0)[0]),
        mix_after=(2, dna_XFR_samp_int * 3),
        blow_out=True,
        blowout_location='destination well')
    # Three tubes created for upper, mid, lower F,R concentrations
    p300.pick_up_tip()
    p300.flow_rate.aspirate = 92.86  #default
    p300.flow_rate.dispense = 92.86  #default
    h = tip_heights(mix_bw_tot - mix_bw_XFR_mix_sn,
                    len(split_asp(mix_bw_XFR_samp_int, p300_max_vol)),
                    408.48)  #split_asp(mix_bw_XFR_samp_int, p300_max_vol)[0])
    p300.mix(2, 200,
             MIX_bw.bottom(4))  # low; need to thoroughly mix DNA in tube
    p300.mix(2, 200,
             MIX_bw.bottom(8))  # mid; need to thoroughly mix DNA in tube
    p300.mix(7, 200,
             MIX_bw.bottom(h[0] - 10))  # need to thoroughly mix DNA in tube
    for tube in samp_tubes:
        for j in range(
                len(split_asp(mix_bw_XFR_samp_int, p300_max_vol))
        ):  # split_asp is a function that returns equally divided aspirations
            p300.flow_rate.aspirate = 40  #default
            p300.flow_rate.dispense = 40  #default
            amt = split_asp(mix_bw_XFR_samp_int, p300_max_vol)[j]
            p300.aspirate(amt, MIX_bw.bottom(2))
            protocol.delay(seconds=2)
            # h = tip_heights(amt+amt*j, 1, 0)[0] # adjust tip height depending on dispenses
            p300.dispense(
                amt,
                tube.bottom(3))  # want tip to be just a little above dispense
            p300.blow_out(tube.bottom(20))  # want to be above liquid level
            p300.touch_tip()
    p300.drop_tip()
    p300.well_bottom_clearance.aspirate = 1  #mm
    p300.well_bottom_clearance.dispense = 1  #mm
    # add F, R primers into samp_int tubes first with upper, mid (p300 vols), then with low (p20 vols)
    for i in range(2):
        h = tip_heights(mix_bw_XFR_samp_int, 1, 0)[0]
        p300.transfer(F_samp_vols[i],
                      fwd_10uM.bottom(2),
                      samp_tubes[i].bottom(h),
                      mix_after=(2, 100),
                      new_tip='always')
        p300.transfer(R_samp_vols[i],
                      rev_10uM.bottom(2),
                      samp_tubes[i].bottom(h),
                      mix_after=(2, R_samp_vols[i]),
                      new_tip='always')
    # F primer to low tube
    p20.transfer(F_samp_vols[-1],
                 fwd_10uM.bottom(2),
                 samp_tubes[-1].bottom(
                     tip_heights(mix_bw_XFR_samp_int, 1, 0)[0]),
                 mix_after=(2, F_samp_vols[-1]),
                 new_tip='always')
    # R primer to low tube
    p20.transfer(R_samp_vols[-1],
                 rev_10uM.bottom(2),
                 samp_tubes[-1].bottom(
                     tip_heights(mix_bw_XFR_samp_int, 1, 0)[0]),
                 mix_after=(2, R_samp_vols[-1]),
                 new_tip='always')

    # add water, dispense samp_int tubes containing F,R, water into plate
    # into each 1st well in plate, A1, B1..F1 then tube_mid into A5, B5..F5
    for i, (tube, wvol) in enumerate(
            zip(samp_tubes, list([water_upp_mix, water_mid_mix,
                                  water_low_mix]))):
        p300.pick_up_tip()
        p300.flow_rate.aspirate = 40  #default
        p300.flow_rate.dispense = 40  #default
        p300.aspirate(wvol, water.bottom(10))
        p300.dispense(wvol, tube.bottom(10))
        p300.flow_rate.aspirate = 92.86  #default
        p300.flow_rate.dispense = 92.86  #default
        p300.mix(2, 200, tube.bottom(4))
        p300.mix(2, 200, tube.bottom(10))
        p300.mix(5, 200, tube.bottom(16.5))
        for j, row in enumerate(plate_rows):
            h = tip_heights(MIX_upp_samp_int, len(plate_rows),
                            mix_samp_XFR_to_well
                            )  #3rd asp is low correct with small tot vol
            print(h)
            dest = row + str(4 * i + 1)
            p300.flow_rate.aspirate = 30
            p300.flow_rate.dispense = 40
            p300.aspirate(mix_samp_XFR_to_well, tube.bottom(h[j]))
            protocol.delay(seconds=2)  # tip equilibrate
            p300.move_to(tube.bottom(25))
            protocol.delay(seconds=2)
            p300.touch_tip(
            )  # bpwd_rxn*row reps (12) * waste = 16.8*12*(1+.12-0.05)=
            p300.dispense(mix_samp_XFR_to_well, plate[dest].bottom(1))
            protocol.delay(seconds=1)
            p300.blow_out(plate[dest].bottom(10))
            p300.touch_tip()
        p300.drop_tip()

    # now that PCR reactions are chillin' at 4C, make Probe int tubes
    # Mix 50ul 'probe' dilutions in tube by adding water and "probe" tube as shown in schedule
    # add water
    p300.pick_up_tip()
    p20.flow_rate.aspirate = 7.56  #default
    p20.flow_rate.dispense = 7.56  #default
    p300.flow_rate.aspirate = 92.86  #default
    p300.flow_rate.dispense = 92.86  #default
    for tube, wvol in zip(probe_mixes[0:4],
                          W_in_mix[0:4]):  # first 4 have vol > 20
        p300.transfer(
            wvol,
            water.bottom(15),
            tube.bottom(1),
            blow_out=False,  #this was creating air bubbles
            blowout_location='destination well',
            new_tip='never')
    p300.drop_tip()
    p20.pick_up_tip()
    # for tube, wvol in probe_mixes[4], W_in_mix[4]:  # 5th item has vol < 20ul
    p20.transfer(W_in_mix[4],
                 water.bottom(15),
                 probe_mixes[4].bottom(1),
                 blow_out=False,
                 blowout_location='destination well',
                 new_tip='never')
    p20.drop_tip()
    # add primer
    p20.pick_up_tip()
    for tube, pvol in zip(probe_mixes[0:3],
                          P_in_mix[0:3]):  # first three tubes have vol < 20ul
        p20.transfer(pvol,
                     probe_10uM.bottom(2),
                     tube.bottom(3),
                     blow_out=False,
                     mix_after=(2, pvol),
                     blowout_location='destination well',
                     new_tip='never')
    p20.drop_tip()
    # next tubes have vol > 20
    p300.pick_up_tip()
    p300.flow_rate.aspirate = 20  #default
    p300.flow_rate.dispense = 40  #default
    for tube, pvol in zip(probe_mixes[3:], P_in_mix[3:]):  # item 3 till end
        p300.transfer(pvol,
                      probe_10uM.bottom(2),
                      tube.bottom(2),
                      blow_out=False,
                      blowout_location='destination well',
                      new_tip='never')
    p300.drop_tip()
    p300.flow_rate.aspirate = 92.86  #default
    p300.flow_rate.dispense = 92.86  #default
    p20.flow_rate.aspirate = 7.56
    p20.flow_rate.dispense = 7.56

    # Add probe to wells. mix, aliquot to adjacent wells
    P_mix_h = tip_heights(P_int_vol, 1, 0)
    for i, (tube, row) in enumerate(zip(probe_mixes, plate_rows)):
        p300.pick_up_tip()
        p20.pick_up_tip()
        p300.flow_rate.aspirate = 60
        p300.flow_rate.dispense = 60  #don't want air bubbles
        p300.mix(3, 30,
                 tube.bottom(P_mix_h[0]))  # mix F primer tube, 100ul in tube
        p300.blow_out(tube.bottom(P_mix_h[0] + 6))
        p300.touch_tip()
        for j in range(2):  # asp and disp into wells
            p20.flow_rate.aspirate = 4
            p20.flow_rate.dispense = 4
            p20.move_to(tube.bottom(40))
            if j == 0:  # wells A1 and A5
                dest = row + str(j + 1)
                nextWell = row + str(j + 5)
                p20.aspirate(
                    p_int_XFR_to_well * 2,
                    tube.bottom(2))  # ~7ul aspirate from P int tube to wells
                protocol.delay(seconds=2)
                p20.move_to(
                    tube.bottom(2))  # relieve pressure if tip against tube
                p20.dispense(p_int_XFR_to_well, plate[dest].bottom(2))
                protocol.delay(seconds=1)
                p20.touch_tip()
                p20.dispense(p_int_XFR_to_well, plate[nextWell].bottom(2))
                protocol.delay(seconds=2)
                p20.blow_out(plate[nextWell].bottom(6))
                p20.touch_tip()
                p20.drop_tip()
                p20.pick_up_tip()
            else:  # well A9
                dest = row + str(j + 8)
                p20.aspirate(
                    p_int_XFR_to_well,
                    tube.bottom(1))  # ~7ul aspirate from P int tube to wells
                p20.move_to(
                    tube.bottom(2))  # relieve pressure if tip against tube
                protocol.delay(seconds=2)
                p20.touch_tip()
                p20.dispense(p_int_XFR_to_well, plate[dest])
                protocol.delay(seconds=2)
                p20.blow_out(plate[dest].bottom(6))
                p20.touch_tip()
        for k in range(
                3):  # need int 0, 1, 2. Looping through bolus in row (3)
            swell = row + str(4 * k + 1)  #source well: A1, A5, A9
            p300.move_to(plate[swell].bottom(30))
            p300.flow_rate.aspirate = 92.86
            p300.flow_rate.dispense = 92.86
            p300.mix(3, 70, plate[swell].bottom(2), rate=0.75)
            p300.flow_rate.aspirate = 40
            p300.flow_rate.dispense = 20
            p300.mix(1, 70, plate[swell].bottom(2),
                     rate=0.6)  #slow mix to avoid/remove bubbles
            p300.blow_out(plate[swell].bottom(10))
            for m in range(1, 4):  # want int 1, 2, 3
                p20.flow_rate.aspirate = 7.56
                p20.flow_rate.dispense = 7.56
                dwell = row + str(
                    4 * k + 1 + m)  # loop through dispensing wells
                p20.move_to(plate[swell].bottom(40))
                p20.aspirate(20, plate[swell].bottom(1))
                protocol.delay(seconds=1)
                p20.dispense(20, plate[dwell].bottom(2))
                protocol.delay(seconds=1)
                p20.move_to(plate[dwell].bottom(6))
                p20.blow_out()
                p20.touch_tip()
        p20.drop_tip()
        p300.drop_tip()
def run(ctx: protocol_api.ProtocolContext):
    global robot
    robot = ctx

    # confirm door is close
    if not ctx.is_simulating():
        confirm_door_is_closed()

    # load labware and modules
    ## ELUTION LABWARE
    if ELUTION_LABWARE not in ELUTION_LW_DICT:
        raise Exception('Invalid ELUTION_LABWARE. Must be one of the \
    following:\nopentrons aluminum biorad plate\nopentrons aluminum nest plate')

    elution_plate = ctx.load_labware(
        ELUTION_LW_DICT[ELUTION_LABWARE], '1',
        'elution plate')

    ## MAGNETIC PLATE LABWARE
    magdeck = ctx.load_module('magdeck', '10')
    magdeck.disengage()

    if MAGPLATE_LABWARE not in MAGPLATE_LW_DICT:
        raise Exception('Invalid MAGPLATE_LABWARE. Must be one of the \
following:\nopentrons deep generic well plate\nnest deep generic well plate\nvwr deep generic well plate')

    magplate = magdeck.load_labware(MAGPLATE_LW_DICT[MAGPLATE_LABWARE])

    ## WASTE LABWARE
    if WASTE_LABWARE not in WASTE_LW_DICT:
        raise Exception('Invalid WASTE_LABWARE. Must be one of the \
    following:\nnest 1 reservoir plate')

    waste = ctx.load_labware(
        WASTE_LW_DICT[WASTE_LABWARE], '11', 'waste reservoir').wells()[0].top(-10)

    ## REAGENT RESERVOIR
    if REAGENT_LABWARE not in REAGENT_LW_DICT:
        raise Exception('Invalid REAGENT_LABWARE. Must be one of the \
    following:\nnest 12 reservoir plate')

    reagent_res = ctx.load_labware(
        REAGENT_LW_DICT[REAGENT_LABWARE], '7', 'reagent reservoir')

    ## TIPS
    # using standard tip definition despite actually using filter tips
    # so that the tips can accommodate ~220µl per transfer for efficiency
    tips300 = [
        ctx.load_labware(
            'opentrons_96_tiprack_300ul', slot, '200µl filter tiprack')
        for slot in ['2', '3', '5', '6', '9','4']
    ]
    tips1000 = [
        ctx.load_labware('opentrons_96_filtertiprack_1000ul', slot,
                         '1000µl filter tiprack')
        for slot in ['8']
    ]

    # reagents and samples
    num_cols = math.ceil(NUM_SAMPLES/8)
    mag_samples_m = magplate.rows()[0][:num_cols]
    mag_samples_s = magplate.wells()[:NUM_SAMPLES]
    elution_samples_m = elution_plate.rows()[0][:num_cols]
    elution_buffer = reagent_res.wells()[0]
    bead_buffer = reagent_res.wells()[1:5]
    wash_sets = [reagent_res.wells()[i:i+2] for i in [5, 7, 9]]

    # pipettes
    m300 = ctx.load_instrument('p300_multi_gen2', 'left', tip_racks=tips300)
    p1000 = ctx.load_instrument('p1000_single_gen2', 'right',
                                tip_racks=tips1000)

    m300.flow_rate.aspirate = 150
    m300.flow_rate.dispense = 300
    m300.flow_rate.blow_out = 300
    p1000.flow_rate.aspirate = 100
    p1000.flow_rate.dispense = 1000
    p1000.flow_rate.blow_out = 1000

    if(DISPENSE_BEADS):
        # premix, transfer, and mix magnetic beads with sample
        ## bead dests depending on number of samples
        bead_dests = bead_buffer[:math.ceil(num_cols/4)]
        dispense_beads(bead_dests,mag_samples_m,m300,tips300)
    else:
        # Mix bead
        mix_beads(7, mag_samples_m,m300,tips300)

    # incubate off and on magnet
    ctx.delay(minutes=5, msg='Incubating off magnet for 5 minutes.')

    ## First incubate on magnet.
    magdeck.engage(height_from_base=22)
    ctx.delay(minutes=5, msg='Incubating on magnet for 5 minutes.')

    # remove supernatant with P1000
    remove_supernatant(mag_samples_s,waste,p1000,tips1000)

    # 3x washes
    wash(wash_sets,mag_samples_m,waste,magdeck,m300,tips300)

    # elute samples
    magdeck.disengage()
    elute_samples(mag_samples_m,elution_samples_m,elution_buffer,magdeck,m300,tips300)

    # track final used tip
    save_tip_info()
    magdeck.disengage()
    finish_run()
Example #12
0
def run(protocol: protocol_api.ProtocolContext):
    ###########################LABWARE SETUP#################################

    tiprack_300 = protocol.load_labware('opentrons_96_tiprack_300ul',
                                        labwarePositions.tiprack_300,
                                        'tiprack 300ul')

    pipette_300 = protocol.load_instrument(
        'p300_single_gen2' if pipette_300_GEN == 'GEN2' else 'p300_single',
        pipette_300_location,
        tip_racks=[tiprack_300])
    pipette_300.flow_rate.dispense = default_flow_rate
    pipette_300.flow_rate.aspirate = default_flow_rate
    pipette_300.starting_tip = tiprack_300.well(
        tiprack_starting_pos['tiprack_300'])

    par2 = protocol.load_labware(par2_type, labwarePositions.par2, 'PAR2')
    trough12 = protocol.load_labware('parhelia_12trough',
                                     labwarePositions.buffers_plate,
                                     '12-trough buffers reservoir')

    black_96 = protocol.load_labware('parhelia_black_96',
                                     labwarePositions.antibodies_plate,
                                     '96-well-plate')

    buffer_wells = trough12.wells_by_name()

    buffers = Object()
    buffers.Hydration_PFA_1pt6pct = buffer_wells['A1']
    buffers.Staining = buffer_wells['A2']
    buffers.Storage_PFA_4pct = buffer_wells['A3']
    buffers.MeOH = buffer_wells['A4']
    buffers.PBS = buffer_wells['A5']
    buffers.CODEX_buffer_1x = buffer_wells['A6']
    buffers.Screening_Buffer = buffer_wells['A7']
    buffers.Stripping_buffer = buffer_wells['A8']
    buffers.storage = buffer_wells['A9']

    preblock_wells = black_96.rows()[0]
    antibody_wells = black_96.rows()[1]
    reagent_F_wells = black_96.rows()[2]
    rendering_wells = black_96.rows()[3]

    sample_chambers = []

    for well in wellslist:
        sample_chambers.append(par2.wells_by_name()[well])

    #################PROTOCOL####################
    protocol.comment("Starting the CODEX staining protocol for samples:" +
                     str(sample_chambers))

    if not FFPE:
        #WASHING SAMPLES WITH PFA
        protocol.comment("first fix")
        washSamples(pipette_300, buffers.Hydration_PFA_1pt6pct,
                    buffers.Hydration_PFA_1pt6pct, 0, 1, extra_bottom_gap)
        washSamples(pipette_300, buffers.Hydration_PFA_1pt6pct,
                    sample_chambers, wash_volume, 1, extra_bottom_gap)
        #INCUBATE
        protocol.delay(minutes=10, msg="first fix incubation")

    #WASHING SAMPLES WITH S2
    protocol.comment("washing in S2")
    washSamples(pipette_300, buffers.Staining, buffers.Staining, 0, 1,
                extra_bottom_gap)
    washSamples(pipette_300, buffers.Staining, sample_chambers, wash_volume, 2,
                extra_bottom_gap)

    #WASHING SAMPLES WITH PREBLOCK
    protocol.comment("preblocking")
    for i in range(len(wellslist)):
        washSamples(pipette_300, preblock_wells[i], sample_chambers[i],
                    wash_volume, 1, extra_bottom_gap)
    #INCUBATE
    protocol.delay(minutes=15, msg="preblocking incubation")

    #APPLYING ANTIBODY COCKTAILS TO SAMPLES
    protocol.comment("applying antibodies")
    for i in range(len(wellslist)):
        washSamples(pipette_300, antibody_wells[i], sample_chambers[i],
                    ab_volume, 1, extra_bottom_gap)
    #INCUBATE
    protocol.delay(minutes=ab_incubation_time_minutes,
                   msg="staining incubation")

    for i in range(2):
        #WASHING SAMPLES WITH Staining buffer
        protocol.comment("first washing with Staining buffer")
        washSamples(pipette_300, buffers.Staining, sample_chambers,
                    wash_volume, 2, extra_bottom_gap)
        #INCUBATE
        protocol.delay(minutes=5, msg="first incubation in Staining Buffer")

    #POST STAINING FIXING SAMPLES WITH PFA
    protocol.comment("second fix")
    washSamples(pipette_300, buffers.Storage_PFA_4pct,
                buffers.Storage_PFA_4pct, 0, 1, extra_bottom_gap)
    washSamples(pipette_300, buffers.Storage_PFA_4pct, sample_chambers,
                wash_volume, 1, extra_bottom_gap)
    #INCUBATE
    protocol.delay(minutes=5, msg="incubation with fixative")

    #WASHING SAMPLES WITH PBS
    protocol.comment("PBS wash")
    washSamples(pipette_300, buffers.PBS, buffers.PBS, 0, 2, extra_bottom_gap)
    washSamples(pipette_300, buffers.PBS, sample_chambers, wash_volume, 2,
                extra_bottom_gap)

    # FIXING SAMPLES WITH Methanol
    washSamples(pipette_300, buffers.MeOH, buffers.MeOH, 0, 1,
                extra_bottom_gap)
    for i in range(2):
        protocol.comment("applying MeOH")
        washSamples(pipette_300, buffers.MeOH, sample_chambers, wash_volume, 1,
                    extra_bottom_gap)
        # INCUBATE
        protocol.delay(minutes=2.5, msg="First MeOH incubation")

    #WASHING SAMPLES WITH PBS
    protocol.comment("PBS wash")
    washSamples(pipette_300, buffers.PBS, sample_chambers, wash_volume, 2,
                extra_bottom_gap)

    #DILUTING AND APPLYING THE FIXATIVE
    for i in range(len(wellslist)):
        dilute_and_apply_fixative(pipette_300, reagent_F_wells[i], buffers.PBS,
                                  sample_chambers[i], 150)

    protocol.comment("third fix incubation")
    protocol.delay(minutes=10, msg="Reagent F incubation")

    #WASHING SAMPLES WITH PBS
    protocol.comment("PBS wash")
    washSamples(pipette_300, buffers.PBS, sample_chambers, wash_volume, 2,
                extra_bottom_gap)

    if Antibody_Screening:
        washSamples(pipette_300, buffers.Stripping_buffer,
                    buffers.Stripping_buffer, 0, 1, extra_bottom_gap)
        washSamples(pipette_300, buffers.Screening_Buffer,
                    buffers.Screening_Buffer, 0, 1, extra_bottom_gap)
        #PRE-CLEARING THE TISSUE
        for i in range(3):
            protocol.comment("tissue clearing round" + str(i + 1))
            washSamples(pipette_300, buffers.Stripping_buffer, sample_chambers,
                        wash_volume, 2, extra_bottom_gap)
            protocol.delay(seconds=30)
            washSamples(pipette_300, buffers.Screening_Buffer, sample_chambers,
                        wash_volume, 1, extra_bottom_gap)
            washSamples(pipette_300, buffers.CODEX_buffer_1x, sample_chambers,
                        wash_volume, 1, extra_bottom_gap)

        #Equilibration in rendering buffer
        protocol.comment("Equilibration in rendering buffer")
        washSamples(pipette_300, buffers.Screening_Buffer, sample_chambers,
                    wash_volume, 1, extra_bottom_gap)

        #RENDERING
        protocol.comment("Applying rendering solution to wells")
        for i in range(len(wellslist)):
            washSamples(pipette_300, rendering_wells[i], sample_chambers[i],
                        wash_volume, 1, extra_bottom_gap)
        #INCUBATE
        protocol.delay(minutes=10, msg="rendering hybridization")

        #WASH SAMPLES IN 1x CODEX buffer
        protocol.comment("Washing with rendering buffer")
        washSamples(pipette_300, buffers.Screening_Buffer, sample_chambers,
                    wash_volume, 2, extra_bottom_gap)

    #STORAGE, washing samples every hour for 100 hours
    washSamples(pipette_300, buffers.storage, buffers.storage, 0, 1,
                extra_bottom_gap)
    for i in range(10):
        washSamples(pipette_300,
                    buffers.storage,
                    sample_chambers,
                    wash_volume / 3,
                    1,
                    extra_bottom_gap,
                    keep_tip=True)
        protocol.delay(minutes=90, msg="storing samples in storage buffer")
def run(protocol: protocol_api.ProtocolContext):

    ################### SETTING UP ###################
    ##                                              ##
    ##     ヽ༼ຈل͜ຈ༽ノ LABWARE ヽ༼ຈل͜ຈ༽ノ               ##
    ##                                              ##
    ##################################################

    # Positions are:
    # 10    11      TRASH
    # 7     8       9
    # 4     5       6
    # 1     2       3

    #Modules, plate and MAGNET HEIGHT
    magneto = protocol.load_module("magneticModuleV2", 6)
    deepPlate = magneto.load_labware("eppendorf_96_deepwell_2ml",
                                     label="Deep well")
    magnetHeight = 6.7
    #########################################################################################################
    ##  We have tested appropriate height on GEN1 magdeck for different plates, these are the chosen ones  ##
    ##                                                                                                     ##
    ##  Zymoresearch - "zymoresearch_96_deepwell_2.4ml" - 12.5mm                                           ##
    ##  Eppendorf - "eppendorf_96_deepwell_2ml" - 11.8 mm                                                  ##
    ##  Starlab - "usascientific_96_wellplate_2.4ml_deep" - E2896-1810 11.4mm                              ##
    ##  Macherey-Nagel - - 10mm                                                                            ##
    #########################################################################################################

    #Plates
    reagents = protocol.load_labware("nest_12_reservoir_15ml",
                                     5,
                                     label="Reagents reservoir")
    waste = protocol.load_labware("nest_12_reservoir_15ml",
                                  9,
                                  label="Liquid waste reservoir")
    outplate = protocol.load_labware("eppendorf96_skirted_150ul",
                                     1,
                                     label="Output plate")
    #Tips - Ordered in the way they are used
    parkingRack = protocol.load_labware("opentrons_96_filtertiprack_200ul", 3)
    tiprack1 = protocol.load_labware("opentrons_96_filtertiprack_200ul", 2)
    tiprack4 = protocol.load_labware("opentrons_96_filtertiprack_200ul", 4)
    tiprack7 = protocol.load_labware("opentrons_96_filtertiprack_200ul", 7)
    tiprack8 = protocol.load_labware("opentrons_96_filtertiprack_200ul", 8)
    tiprack10 = protocol.load_labware("opentrons_96_filtertiprack_200ul", 10)

    tipracks = [tiprack10, tiprack8, tiprack7, tiprack4, tiprack1]
    availableTips = []
    for rack in tipracks:
        for i in range(1, 13):
            availableTips.append(rack["A" + str(i)])
    #To take a tip, just use availableTips.pop() and voila!
    #There are enough tips for 6 samples, and a tiprack will end up half-full
    #Tips are taken from right to left instead of the normal way
    #I am using this dictionary method because it makes it easier to modify later the script for 96 samples/

    #Pipettes
    p300 = protocol.load_instrument("p300_multi_gen2", "left")

    ################### SETTING UP ###################
    ##                                              ##
    ## ヽ༼ຈل͜ຈ༽ノ BASIC VARIABLES ヽ༼ຈل͜ຈ༽ノ             ##
    ##                                              ##
    ##################################################

    #RUN SETTINGS
    runColumns = 3  # Range 1-6. Samples should be a multiple of 8, or you will waste reagents.
    mixRepeats = 15  # Used everytime there is mixing, except when mixing beads.
    beadsMixRepeats = 10  # Used when mixing beads in reservoir. This happens when pipetting column 1, 3 and 6.
    waterMixRepeats = 20  # Used when mixing elute.

    #Mixing settings
    washMixing = 100  # volume (ul)
    waterMixing = 25  # volume (ul)
    bottomHeight = 0.5  # Distance relative to real labware's bottom. Used when removing supernatant and moving elution.
    bottomMixHeight = 0.8  # Distance relative to real labware's bottom. Used when mixing
    SamplePlusProteinaseHeight = 3  # For a volume of 260..
    SamplePlusProteinasePlusBeadsHeight = 5.75  # For a volume of 465...
    generalHeight = 4  # Used always except when mixing beads in reservoir - Units relative to well bottom (mm). For a vol of 280...
    beadsHeight = 10  # Used when mixing beads in reservoir - Units relative to well bottom (mm). When mixing beads in the reagent well - Maybe I should modify this and make it depend on runColumns

    #Incubation times - Minutes
    incubationProteinase = 10
    incubationBeadsNoMagnet = 5  # After adding the beads, we incubate them for 5 min without magnet.
    incubationBeadsMagnet = 5 * 2
    incubationWash = 3 * 2
    incubationDry = 10  # After removing final wash, the beads are left to dry for a while.
    incubationWater = 5  # After mixing. No magnet.
    incubationWaterMagnet = 1 * 2  # After incubationWater.

    #Transference volumes - ul
    originalVol = 140  #This is not used for transfers, it is here mostly to make volumes clearer to understand
    proteinaseVol = 112
    beadsVol = 143.5
    washVol = 280  #Used for WBE and Ethanol1 and Ethanol2
    dilutionVol = 50
    initialSupernatant = originalVol + proteinaseVol + beadsVol

    #Reagent position in reservoir - Positions go from A1 to A12 (Left to right)
    proteinase = reagents["A1"]
    beads = reagents["A2"]
    WBE = reagents["A3"]
    ethanol1 = reagents["A4"]
    ethanol2 = reagents["A5"]
    water = reagents["A12"]
    #########################################################################################################
    ##           Use these formulae to identify how much volume you need based on number of columns        ##
    ##           Each reservoir well has dimensions W=8.20, L=127.76, H=31.40. To make sure there is       ##
    ##           a pool of extra content with 0.5mm of height, add 292ul (300) extra (8.20*127.76*0.05)    ##
    ##                                                                                                     ##
    ##  Proteinase = (896 * runColumns) + 292 ul                                                           ##
    ##  Beads = (1152 * Columns) + 292 ul                                                                  ##
    ##  WBE = (2240 * Columns) + 292 ul                                                                    ##
    ##  Ethanol1 = (2240 * Columns) + 292 ul                                                               ##
    ##  Ethanol2 = (2240 * Columns) + 292 ul                                                               ##
    ##  Water = (640 * Columns) + 292 ul                                                                   ##
    #########################################################################################################

    ################### SETTING UP ###################
    ##                                              ##
    ## ヽ༼ຈل͜ຈ༽ノ ADVANCED VARIABLES ヽ༼ຈل͜ຈ༽ノ          ##
    ##                                              ##
    ##################################################

    #Column accesion list - As we wont work in all physically available columns, this list makes it easier to manage
    columnID = ["A1", "A3", "A5", "A7", "A9",
                "A11"]  # These are the columns that can be used
    columnID = columnID[:
                        runColumns]  # Here we trim the list, to get only the number of columns chosen in runColumns

    #Pipette settings
    tipVolume = 180  # max volume to be transported in a single trip. These tips are 200ul, but if we use the entire volumen, it might touch the filter
    topOffset = -5  # I use this to make sure the tip stays inside the well, to avoid it spilling out while dispensing
    p300.flow_rate.aspirate = 50  # Flow rate in ul / second
    p300.flow_rate.dispense = 150
    p300.flow_rate.blow_out = 200
    #Flows are reduced compared to default values to avoid the production of air or foam during handling.

    #Volume used when mixing beads (ul)
    if runColumns == 1:
        beadsMixing = 140
    else:
        beadsMixing = tipVolume

    ################### SETTING UP ###################
    ##                                              ##
    ##(づ。◕‿‿◕。)づ    FUNCTIONS    (づ。◕‿‿◕。)づ ##
    ##                                              ##
    ##################################################
    def clock(time, stop=False):
        """
        The uncertainty of not knowing how much time is left in an incubation is horrible. This makes it more bearable.
        This function takes the duration of the incubation and outputs a message every minute to keep track of the time more easily
        """
        while time > 0:
            time -= 1
            protocol.delay(minutes=1)
            protocol.comment("Only %s minutes more! Hold in there!" % time)
            if time == 1 and stop == True:
                protocol.pause()

    def meneillo(pipette, pos, reps=10, distance=0.25):
        pipette.move_to(pos)
        for _ in range(reps):
            p300.move_to(pos.move(types.Point(x=distance, y=0, z=0)))
            p300.move_to(pos.move(types.Point(x=-distance, y=0, z=0)))

    def remove_tip(pipette, tip):
        """
        Originally, I had a special behaviour to drop the tips, but I stopped using it.
        I keep this function because it makes it easy to change drop_tip() to return_tip() for test runs
        """
        pipette.drop_tip()

    def retrieve_tip(pipette, tip):
        """
        Originally, the robot took a tip, went to the top of the well it was going to work with, and aspired 20 ul there, but now we are making it aspire 20 ul after taking the tip
        """
        pipette.pick_up_tip(tip)

    def well_mix(vol,
                 loc,
                 reps,
                 height=generalHeight,
                 moveSide=0,
                 bottomHeight=bottomMixHeight):
        """
        Aspirates <vol> from bottom of well and dispenses it from <height> <reps> times
        loc1 is a position at 0.3mm over the bottom of the well
        loc2 is a position in the same x and y posiiton than loc1, but at <height>mm over the bottom of the well
        The idea here is to take liquid to the very bottom and pour it from a higher point, to mix things
        """
        p300.flow_rate.aspirate = 1000
        p300.flow_rate.dispense = 1000
        loc1 = loc.bottom().move(
            types.Point(x=0 + moveSide, y=0, z=bottomHeight))
        loc2 = loc.bottom().move(types.Point(x=0 + moveSide, y=0, z=height))
        for _ in range(reps):
            p300.aspirate(vol, loc1)
            p300.dispense(vol, loc2)
        p300.dispense(20, loc.top(topOffset))
        p300.flow_rate.aspirate = 50
        p300.flow_rate.dispense = 150

    def remove_supernatant(vol,
                           columnID,
                           wasteID,
                           reagentName="Something",
                           pipette=p300):
        """
        While <vol> is bigger than <tipVolume>, it divides it in ceilling(<vol>/<tipVolume>) trips. (So, if it is 396ul, we have 2 180ul trips and a 36ul trip)
        Flow rate is in ul/second
        In the move() function, positive X means 'move to the right'. With the wells we use (Column 1,3,5,7,9 and 11) pellet is placed to the right, so we use a small offset to the left
        """
        p300.flow_rate.aspirate = 20  # In this case we reduce the flow even more to make sure the precipitate is okay. We don't wanna bother the lad
        protocol.comment(
            "\n\nREMOVING STEP: Removing %s ul of supernatant (%s) while magnet is still engaged"
            % (vol, reagentName))
        dump = waste[wasteID]
        for index, ID in enumerate(columnID):
            currentip = parkingRack[ID]
            dump = waste[ID]
            src = deepPlate[ID]
            retrieve_tip(pipette, currentip)
            tvol = vol
            while tvol > tipVolume:
                p300.dispense(20, src.top(topOffset))
                p300.transfer(tipVolume,
                              src.bottom().move(
                                  types.Point(x=-1, y=0, z=bottomHeight)),
                              dump.top(topOffset),
                              new_tip="never")  #Slightly to the left
                meneillo(
                    p300, dump.top(topOffset)
                )  #In case something is TheOppositeOfDense and just drips down
                p300.dispense(
                    20
                )  #Make sure we expel everything that must be expelled. We dont want to move droplets around.
                tvol -= tipVolume
            p300.dispense(20, src.top(topOffset))
            p300.transfer(tvol,
                          src.bottom().move(
                              types.Point(x=-1, y=0, z=bottomHeight)),
                          dump.top(topOffset),
                          new_tip="never")
            meneillo(p300, dump.top(topOffset))
            remove_tip(pipette, currentip)
        p300.flow_rate.aspirate = 50

    def slow_transfer(vol,
                      reagent,
                      columnID,
                      reagentName,
                      mixVol=washMixing,
                      repeats=mixRepeats,
                      mixReagent=False,
                      altura=generalHeight,
                      magnetTime=True,
                      incubationTime=incubationWash,
                      moveSide=0,
                      extraVol=0,
                      pipette=p300,
                      removalStepAfter=True):
        """
        Similar to remove_supernatant, but the other way around. It transfers from point A to point B in <tipVol> ul trips and pours liquid
        from the top, to avoid contaminating the tip while transfering all the necessary volume.
        It also includes incubation and magnet
        """
        protocol.comment(
            "\n\nADDING STEP: Transfering %s ul of %s to samples" %
            (vol, reagentName))
        for index, ID in enumerate(columnID):
            src = reagent
            to = deepPlate[ID]
            currentip = availableTips.pop()
            retrieve_tip(p300, currentip)
            if (mixReagent == True) and (
                    index == 0 or index == 2 or index == 5
            ):  #If the reagent is to be mixed, and we are in column 1, 3 or 6, mix it. We mix three times to make sure we dont have differences
                protocol.comment("Mixing %s" % reagentName)
                well_mix(
                    vol=beadsMixing,
                    loc=beads,
                    reps=beadsMixRepeats,
                    height=beadsHeight,
                    moveSide=0
                )  #We only do this with magnetic beads, that's why we use those variable names
                p300.blow_out(beads.top())
            tvol = vol
            while tvol > tipVolume:
                p300.dispense(20, src.top())
                p300.transfer(tipVolume,
                              src.bottom().move(
                                  types.Point(x=0, y=0, z=bottomHeight)),
                              to.top(topOffset),
                              new_tip="never",
                              air_gap=extraVol)
                protocol.delay(seconds=2)
                p300.blow_out()
                tvol -= tipVolume
            p300.dispense(20, src.top())
            p300.transfer(tvol,
                          src.bottom().move(
                              types.Point(x=0, y=0, z=bottomHeight)),
                          to.center(),
                          new_tip="never",
                          air_gap=extraVol)
            protocol.delay(seconds=2)
            well_mix(vol=mixVol,
                     loc=to,
                     reps=repeats,
                     moveSide=moveSide,
                     height=altura)
            if removalStepAfter == True:
                pipette.drop_tip(parkingRack[ID])
            else:
                remove_tip(pipette, currentip)

        #Incubation
        if magnetTime == True:
            protocol.comment("Engaging magnet")
            magneto.engage(height=magnetHeight)
        protocol.comment("Incubating for %s minutes" % incubationTime)
        clock(time=incubationTime)

    ################# GO, VASILY, GO #################
    ##                                              ##
    ##      ୧༼ಠ益ಠ༽୨    PROTOCOL    ୧༼ಠ益ಠ༽୨        ##
    ##                                              ##
    ##################################################

    magneto.disengage()  #In case it is engaged from previous protocols.
    protocol.comment("We are working with column IDs: %s" % columnID)
    protocol.comment("\n\nSamples should have an initial volume of %s ul" %
                     originalVol)

    #STEP 1: Add Proteinase K/LBF.
    slow_transfer(vol=proteinaseVol,
                  reagent=proteinase,
                  reagentName="Proteinase K/LBF",
                  incubationTime=incubationProteinase,
                  columnID=columnID,
                  magnetTime=False,
                  altura=SamplePlusProteinaseHeight,
                  removalStepAfter=False)
    #INCUBATION 1: 10 min [Total: 10 min]

    #STEP 2: mix magnetic beads, add them to samples and mix sample well. No slow_transfer function for the same reasons as before.
    protocol.comment("\n\nEnough incubation, time to do s t u f f")
    slow_transfer(vol=beadsVol,
                  reagent=beads,
                  reagentName="Magnetic beads",
                  incubationTime=incubationBeadsNoMagnet,
                  columnID=columnID,
                  mixReagent=True,
                  magnetTime=False,
                  extraVol=10,
                  altura=SamplePlusProteinasePlusBeadsHeight)
    #INCUBATION 2: 5 min without magnet [Total: 15 min]
    protocol.comment(
        "Engaging magnet and keeping this incubation going for other %s minutes"
        % incubationBeadsMagnet)
    magneto.engage(height=magnetHeight)
    clock(time=incubationBeadsMagnet, stop=True)
    #INCUBATION 3: 5 min incubation with magnet [Total: 20 min]

    #STEP 3: Remove magnetic beads supernatant
    remove_supernatant(vol=initialSupernatant,
                       wasteID="A1",
                       reagentName="beads and proteinase",
                       columnID=columnID)
    protocol.comment("Disengaging magnet")
    magneto.disengage()

    #STEP 4: Add 280 ul of Wash WBE
    slow_transfer(vol=washVol,
                  reagent=WBE,
                  reagentName="WBE",
                  incubationTime=incubationWash,
                  columnID=columnID)
    #INCUBATION 4: 3 min incubaton with magnet [Total: 23 min]

    #STEP 5: Removing WBE Supernatant
    remove_supernatant(vol=washVol,
                       wasteID="A2",
                       reagentName="WBE",
                       columnID=columnID)
    protocol.comment("Disengaging magnet")
    magneto.disengage()

    #STEP 6: First wash with Eth, tips_transfer)anol
    slow_transfer(vol=washVol,
                  reagent=ethanol1,
                  reagentName="Ethanol 70% (First time)",
                  incubationTime=incubationWash,
                  columnID=columnID)
    #INCUBATION 5: 3 min incubaton with magnet [Total: 26 min]

    #STEP 7: Removing the supernatant of first wash with Ethanol
    remove_supernatant(vol=washVol,
                       wasteID="A3",
                       reagentName="Ethanol 70% (First time)",
                       columnID=columnID)
    protocol.comment("Disengaging magnet")
    magneto.disengage()

    #STEP 8: Second wash with Ethanol
    slow_transfer(vol=washVol,
                  reagent=ethanol2,
                  reagentName="Ethanol 70% (Second time)",
                  incubationTime=incubationWash,
                  columnID=columnID)
    #INCUBATION 6: 3 min incubaton with magnet [Total: 26 min]

    #STEP 9: Removing the supernatant of second wash with Ethanol
    remove_supernatant(vol=washVol,
                       wasteID="A4",
                       reagentName="Ethanol 70% (Second time)",
                       columnID=columnID)
    #INCUBATION 7: 5 min incubaton with magnet [Total: 31 min]
    protocol.comment(
        "This time, I do not disengage the magnet and let the beads dry for %s min"
        % incubationDry)
    clock(time=incubationDry)

    #STEP 10: Diluting samples in 80 ul of RNAse free water
    protocol.comment("Disengaging magnet")
    magneto.disengage()
    protocol.comment("Diluting samples in %s ul of RNAse free water" %
                     dilutionVol)
    slow_transfer(vol=dilutionVol,
                  reagent=water,
                  reagentName="RNAse-free water",
                  incubationTime=incubationWater,
                  columnID=columnID,
                  mixVol=waterMixing,
                  magnetTime=False,
                  repeats=waterMixRepeats)  #Moving tip on top of pellet
    #INCUBATION 8: 5 min incubaton WITHOUT magnet [Total: 36 min]
    protocol.comment("Engaging magnet now!")
    magneto.engage(height=magnetHeight)
    clock(time=incubationWaterMagnet)
    #INCUBATION 9: 3 min incubaton WITH magnet [Total: 39 min]

    #STEP 11: Transfering samples to output plate
    protocol.comment(
        "Transfering DNA to output plate while magnet is still engaged")
    p300.flow_rate.aspirate = 20
    for index, ID in enumerate(columnID):
        currentip = availableTips.pop()
        retrieve_tip(p300, currentip)
        src = deepPlate[ID]
        to = outplate[ID]

        p300.dispense(20, src.top())
        p300.transfer(dilutionVol,
                      src.bottom().move(types.Point(x=-1, y=0,
                                                    z=bottomHeight)),
                      to.bottom(5),
                      new_tip="never")
        protocol.delay(seconds=2)
        p300.dispense(20)
        remove_tip(p300, currentip)

    magneto.disengage()
    protocol.comment("\n\nFecho!")
Example #14
0
def run(protocol: protocol_api.ProtocolContext):
    temp_module = protocol.load_module('Temperature Module', 5)

    p10rack = protocol.load_labware('opentrons_96_tiprack_10ul', 9)
    reagents = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap', 8)
    prep_plate = temp_module.load_labware('nest_96_wellplate_200ul_flat')
    sample_plate = protocol.load_labware('nest_96_wellplate_200ul_flat', 6)
    LbCas_plate = protocol.load_labware('nest_96_wellplate_200ul_flat', 2)

    # Using 10ul pipette for precision
    p10 = protocol.load_instrument('p10_single', 'left', tip_racks=[p10rack])


    base_recipe = { # reagent name: [postion on tuberack, uls to each sample]
                    '10X_IsoAmp_Buffer_NEB': ['A3', 2.5],
                    'MgSO4_NEB': ['B3', 1.13],
                    'dNTPs_NEB': ['C3', 3.5],
                    '10X_Primer_Mix': ['D3', 2.5],
                    'Bst_20_polymerase': ['A4', 1],
                    'Warmstart_RTx': ['B4', 0.5],
                    'water': ['D1', 3.87],
                    '10X_NEBuffer_21': ['A1', 80],
    }

    LbCas_vol_to_load = 2
    LbCas_recipe = {  # reagent name: [postion on tuberack, uls to each sample]
        'LbCas12a_RNP_complex_N-gene': ['A1', LbCas_vol_to_load],
        'LbCas12a_RNP_complex_E-gene': ['A2', LbCas_vol_to_load],
        'LbCas12a_RNP_complex_RNase_P': ['A3', LbCas_vol_to_load]
    }

    sample_vol_to_load = 5
    sample_plate_wells = ['A1']
    sample_plate_locations = [
        sample_plate.wells(well) for well in sample_plate_wells
    ]

    prep_plate_wells = ['A1', 'A2',
                        'A3']  #1st: N-gene wells, 2nd: E-gene, 3rd: RNase P
    prep_plate_locations = [
        prep_plate.wells(well) for well in prep_plate_wells
    ]

    buffer_recipe = base_recipe[
        '10X_NEBuffer_21']  #move reporter to be used later

    #Begin Procedure ---------------------------------------------------------
    for reagent in base_recipe:  #TODO Don't need for-loop, can do with .distribute only
        p10.distribute(
            base_recipe[reagent][1],  #volume
            reagents.wells(base_recipe[reagent][0]),  #source location
            prep_plate_locations)  #dest location

    for source_location in sample_plate_locations:
        p10.transfer(
            sample_vol_to_load,
            source_location,
            prep_plate_locations,  #TODO Handle mutliple-sample case
            mix_after=(2, 10))

    temp_module.set_temperature(62)  #robot pauses until temperature is reached
    protocol.delay(minutes=20)

    #cooling before loading next reagents to not expose LbCas12a solution high temps
    temp_module.set_temperature(37)
    #    print(prep_plate_locations)
    for gRNA in LbCas_recipe:
        p10.distribute(LbCas_recipe[gRNA][1],
                       reagents.wells(LbCas_recipe[gRNA][0]),
                       prep_plate_locations)

    p10.transfer(buffer_recipe[1],
                 reagents.wells(buffer_recipe[0]),
                 prep_plate_locations,
                 mix_after=(2, 10))

    protocol.delay(minutes=10)

    print(
        """Insert Milenia HybridDetect 1 (TwistDx) lateral flow strip directly into each sample
            Wait 2 minutes at room temp
            Observe results""")

    temp_module.set_temperature(25)
    temp_module.deactivate()
def run(protocol: protocol_api.ProtocolContext):

    # LABWARE
    fuge_rack = protocol.load_labware('vwr_24_tuberack_1500ul', '1')
    stds_rack = protocol.load_labware('vwr_24_tuberack_1500ul', '2')
    tiprack300 = protocol.load_labware('opentrons_96_filtertiprack_200ul', '8')
    tiprack20 = protocol.load_labware('opentrons_96_filtertiprack_20ul', '9')
    tempdeck = protocol.load_module('tempdeck', '10')
    # plate = tempdeck.load_labware('amplifyt_96_aluminumblock_300ul')
    plate = tempdeck.load_labware('abi_96_wellplate_250ul')

    # PIPETTES
    p300 = protocol.load_instrument('p300_single_gen2',
                                    'left',
                                    tip_racks=[tiprack300])
    p20 = protocol.load_instrument('p20_single_gen2',
                                   'right',
                                   tip_racks=[tiprack20])

    # REAGENTS
    # sds_rack
    pos_control = stds_rack['A1']  #900ul, 1uM ssDNA
    sN_mix = stds_rack['D1']  # empty; receives BPW_mix and water for stds
    std_1 = stds_rack['A3']  # 990ul Water
    std_2 = stds_rack['A4']  # 900ul water
    std_3 = stds_rack['A5']  # 900ul water
    std_4 = stds_rack['A6']  # 900ul water
    std_5 = stds_rack['B3']  # 900ul water
    std_6 = stds_rack['B4']  # 900ul water
    std_7 = stds_rack['B5']  # 900ul water
    std_1mix = stds_rack['C3']  # empty
    std_2mix = stds_rack['C4']  # empty
    std_3mix = stds_rack['C5']  # empty
    std_4mix = stds_rack['C6']  # empty
    std_5mix = stds_rack['D3']  # empty
    std_6mix = stds_rack['D4']  # empty
    std_7mix = stds_rack['D5']  # empty
    NTC_mix = stds_rack['D6']  # empty, receives sN_mix and water as NTC

    #fuge_rack
    bpwd_mix = fuge_rack['A1']  #empty
    liquid_trash = fuge_rack['B1']
    water = fuge_rack['B2']  # 1700ul water used for neg controls and dilutions
    BPW_mix = fuge_rack[
        'D1']  # see sheet, but gen around 1705 ul; use 2mL tube
    fwd_10uM = fuge_rack['C2']  # min 300ul
    rev_10uM = fuge_rack['D2']  # min 300ul
    fwd_1 = fuge_rack['A4']  # e.g. 0.625uM # empty
    fwd_2 = fuge_rack['A5']  # e.g. 1.25uM # empty
    fwd_3 = fuge_rack['A6']  # e.g. 2.5uM # empty
    fwd_4 = fuge_rack['B4']  # e.g. 5.0uM # empty
    fwd_5 = fuge_rack['B5']  # e.g. 7.5uM # empty
    fwd_6 = fuge_rack['B6']  # e.g. 10uM # empty
    R_mix_1 = fuge_rack['C4']  # e.g. 0.625uM # empty
    R_mix_2 = fuge_rack['C5']  # e.g. 1.25uM # empty
    R_mix_3 = fuge_rack['C6']  # e.g. 2.5uM # empty
    R_mix_4 = fuge_rack['D4']  # e.g. 5.0uM # empty
    R_mix_5 = fuge_rack['D5']  # e.g. 7.5uM # empty
    R_mix_6 = fuge_rack['D6']  # e.g. 10uM # empty

    # lists
    plate_col = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
    all_R_mix = [R_mix_1, R_mix_2, R_mix_3, R_mix_4, R_mix_5, R_mix_6]
    plate_rows = ['A', 'B', 'C', 'D', 'E', 'F']
    all_fwd = [fwd_1, fwd_2, fwd_3, fwd_4, fwd_5, fwd_6]
    std_tubes = [std_1, std_2, std_3, std_4, std_5, std_6, std_7, water]
    std_mixes = [
        std_1mix, std_2mix, std_3mix, std_4mix, std_5mix, std_6mix, std_7mix,
        NTC_mix
    ]
    std_wells = ['G1', 'G4', 'G7', 'G10', 'H1', 'H4', 'H7', 'H10']

    # user inputs
    orig_F_conc = 10  # What is the starting F primer concentration? (in uM)
    orig_R_conc = 10  # What is the starting R primer concentration? (in uM)
    orig_P_conc = 10  # What is probe starting concentration? (in uM)
    std_F_conc = 300  # What is the constant F primer concentration for standards? This should be guess or from literature. (in nM)
    std_R_cond = 300  # What is the constant R primer concentration for standards? This should be guess or from literature. (in nM)
    P_conc = 300  # What is the probe concentration? This should be constant throughout experiment.
    tot_stds = 21  # How many wells of standards will be run? (in # wells)
    tot_NTCs = 3  # How many wells of NTCs will be run? (in # wells)
    tot_samp = 72  # How many samples with varying conditions will be run? (in # wells)
    rxn_base = 11.2  # Everything in PCR buffer (Mg2+, dNTPs, polymerase, enhancers, stabilizers, sugars, etc.). (in uL)
    tot_rxn_vol = 20  # What is total volume of PCR reaction in plate/tube? (in ul)
    # F_concs = [50, 100, 200, 400, 600, 800] # What are the F primer concentrations? (a list in nM)
    # R_concs = [50, 100, 200, 400, 600, 800] # What are the R primer concentrations? (a list in nM)
    F_50 = 50  # F primer at lowest concentration. (in nM)
    F_100 = 100  # F primer at concentration. (in nM)
    F_200 = 200  # F primer at concentration. (in nM)
    F_400 = 400  # F primer at concentration. (in nM)
    F_600 = 600  # F primer at concentration. (in nM)
    F_800 = 800  # F primer at highest concentration. (in nM)
    R_50 = 50  # R primer at lowest concentration. (in nM)
    R_100 = 100  # R primer at concentration. (in nM)
    R_200 = 200  # R primer at concentration. (in nM)
    R_400 = 400  # R primer at concentration. (in nM)
    R_600 = 600  # R primer at concentration. (in nM)
    R_800 = 800  # R primer at highest concentration. (in nM)
    dna_per_rxn = 2  # How much standard, positive control or NTC to add per well.
    std_NTC_reps = 3  # How many standard and NTC replicates? (int)
    R_reps = 12  # How many wells will use R primer at particular concentration? (int)
    # F_reps = 12 # How many wells will use F primer at particular concentration? (int)
    F_int_vol = 100  # What is the volume of F intermediate primer in new tube? (in ul)
    percent_waste = 0.20  # What percentage waste? (decimal)
    sN_mix_waste_offset = 0.025  # How much percent_waste offset should sN_mix use? This calculated as percent_waste-sN_mix_overage = percent_waste for sN_mix_overage e.g. (20-7=13%) Should not be 0 otherwise offset = percent_waste. (decimal)
    R_mix_waste_offset = 0.10  # How much percent_waste offset should R_mix use? This calculated as percent_waste-R_mix_overage = percent_waste for R_mix_overage e.g. (20-=13%) If 0, then offset = percent_waste. (decimal)
    std_NTC_waste_offset = 0.028  # How much percent_waste offset should std_NTC use? (decimal)
    bpw_waste_offset = 0.032  # How much percent_waste offset should bpw_waste use? (decimal)
    p300_max_vol = 200

    # calcs
    tot_rxns = tot_stds + tot_NTCs + tot_samp  # Calc what is total # rxns. (int)
    tot_sds_NTC = tot_stds + tot_NTCs  # Calc number of standards and nontemplate controls. (int)
    rxn_vol_no_dna = tot_rxn_vol - dna_per_rxn  # Calc what is volume of PCR rxn with no DNA added. (in ul)
    P_per_rxn = P_conc / 1000 * tot_rxn_vol / orig_P_conc  # Calc this constant probe is needed per pcr reaction. (in ul)
    max_vol_F_per_rxn = F_800 / 1000 * tot_rxn_vol / orig_F_conc  # Calc greatest vol added from starting F primer conc to rxn to satisfy max test F conc? (in ul)
    max_vol_R_per_rxn = R_800 / 1000 * tot_rxn_vol / orig_R_conc  # Calc greatest vol added from starting R primer conc to rxn to satisfy max test R conc? (in ul)
    water_per_rxn = rxn_vol_no_dna - rxn_base - P_per_rxn - max_vol_F_per_rxn - max_vol_R_per_rxn  # Calc this is water added per rxn such that greatest F, R primer conc can be accommodated in total rxn vol. (in ul)
    std_vol_F_per_rxn = std_F_conc / 1000 * tot_rxn_vol / orig_F_conc  # Calc adding this much F primer to each std rxn
    std_vol_R_per_rxn = std_R_cond / 1000 * tot_rxn_vol / orig_R_conc  # Calc adding this much F primer to each std rxn
    BPW_rxn = rxn_base + P_per_rxn + water_per_rxn  # Mix base + probe + water (no DNA, F, R primer). (in ul)
    std_woff_per_sN_rxn = max_vol_F_per_rxn - std_vol_F_per_rxn + max_vol_R_per_rxn - std_vol_R_per_rxn  # Calc how much water to add to offset diff in max vol F,R primer per reaction. (Max-Std)*2 (in ul)
    BPW_sN_rxn = BPW_rxn + std_vol_F_per_rxn + std_vol_R_per_rxn + std_woff_per_sN_rxn  # Mix base + probe + water+F,R primer at std conc+water_offset(no DNA). (in ul)
    BWP_mix_xfer_sN_mix = tot_sds_NTC * (
        1 + percent_waste - sN_mix_waste_offset
    ) * BPW_rxn  # Calc how much tot_BPW_mix to move to make new tube for stds and NTC. (in ul)
    std_woff_add_to_sN_mix = std_woff_per_sN_rxn * tot_sds_NTC * (
        1 + percent_waste - sN_mix_waste_offset
    )  # Calc how much water to add to sdd_NTC mmix with waste
    F_add_to_sN_mix = tot_sds_NTC * (
        1 + percent_waste - sN_mix_waste_offset
    ) * std_vol_F_per_rxn  # Calc how much F primer to add to std_NTC mmix with waste
    R_add_to_sN_mix = tot_sds_NTC * (
        1 + percent_waste - sN_mix_waste_offset
    ) * std_vol_R_per_rxn  # Calc how much R primer to add to std_NTC mmix with waste
    sN_mix_xfer_to_stds_mix = BPW_sN_rxn * std_NTC_reps * (
        1 + percent_waste - std_NTC_waste_offset
    )  # Calc how much sn_mix to aliquot to tube in preparation for std DNA mixing. (in ul)
    std_DNA_xfer_to_stds_mix = dna_per_rxn * std_NTC_reps * (
        1 + percent_waste - std_NTC_waste_offset
    )  # Calc how much DNA from each standard adding to stds_mix with waste. (in ul)
    bpw_mix_xfer_bpwd_mix = tot_samp * BPW_rxn * (
        1 + percent_waste - bpw_waste_offset
    )  # Calc how much bpw_mix needed in new tube for # total samples
    std_DNA_xfer_to_bpwd_mix = dna_per_rxn * tot_samp * (
        1 + percent_waste - bpw_waste_offset
    )  # Calc how much DNA to add to bpw_mix for template in PCR rxns.
    dna_per_rxn_10x = 0.2  # dna_per_rxn_10x =  # 10x concentrated DNA to add to reactions to avoid using too much std sample
    water_per_rxn_bpwd_mix = 2 - dna_per_rxn_10x  # water_per_rxn_bpwd_mix =  # Water to add to bpwd mix to offset 2ul to 0.2ul DNA addition.
    dna_XFR_bpwd_mix = tot_samp * dna_per_rxn_10x * (
        1 + percent_waste - bpw_waste_offset
    )  # dna_XFR_bpwd_mix =  # The amount of DNA to transfer from a std tube to the bpwd_mix
    water_XFR_bpwd_mix = tot_samp * water_per_rxn_bpwd_mix * (
        1 + percent_waste - bpw_waste_offset
    )  # water_XFR_bpwd_mix =  # The amount of water to transfer to the bpwd_mix to offset lower DNA vol addition
    bpwd_rxn = BPW_rxn + dna_per_rxn  # Calc vol of bpw reaction + DNA vol
    bpwd_mix_xfer_R_mix = bpwd_rxn * R_reps * (
        1 + percent_waste - R_mix_waste_offset
    )  # Calc how muc bpwd_mix to transfer to each tube for specific R conc. Less than 12% to avoid missing vol.
    R_50_rxn = R_50 / 1000 * tot_rxn_vol / orig_R_conc  # Calc how much R primer at lowest concentration to add per reaction? (e.g. 50nM) (in ul)
    R_50_mix = R_50_rxn * R_reps * (
        1 + percent_waste - R_mix_waste_offset
    )  # Calc how much R primer to add to R_50 mix. (in ul)
    R_50_woff_rxn = max_vol_R_per_rxn - R_50_rxn  # Calc how much water offset to add to each rxn. (in ul)
    R_50_woff_mix = R_50_woff_rxn * R_reps * (
        1 + percent_waste - R_mix_waste_offset
    )  # Calc how much water offset to add to R_50 mix. (in ul)
    R_100_rxn = R_100 / 1000 * tot_rxn_vol / orig_R_conc  # Calc how much R primer at concentration to add. (in ul)
    R_100_mix = R_100_rxn * R_reps * (
        1 + percent_waste - R_mix_waste_offset
    )  # Calc how much R primer to add to add. (in ul)
    R_100_woff_rxn = max_vol_R_per_rxn - R_100_rxn  # Calc how much water offset to add to each rxn. (in ul)
    R_100_woff_mix = R_100_woff_rxn * R_reps * (
        1 + percent_waste - R_mix_waste_offset
    )  # Calc how much water offset to add to mix. (in ul)
    R_200_rxn = R_200 / 1000 * tot_rxn_vol / orig_R_conc  # Calc how much R primer at concentration to add. (in ul)
    R_200_mix = R_200_rxn * R_reps * (
        1 + percent_waste - R_mix_waste_offset
    )  # Calc how much R primer to add to add. (in ul)
    R_200_woff_rxn = max_vol_R_per_rxn - R_200_rxn  # Calc how much water offset to add to each rxn. (in ul)
    R_200_woff_mix = R_200_woff_rxn * R_reps * (
        1 + percent_waste - R_mix_waste_offset
    )  # Calc how much water offset to add to mix. (in ul)
    R_400_rxn = R_400 / 1000 * tot_rxn_vol / orig_R_conc  # Calc how much R primer at concentration to add. (in ul)
    R_400_mix = R_400_rxn * R_reps * (
        1 + percent_waste - R_mix_waste_offset
    )  # Calc how much R primer to add to add. (in ul)
    R_400_woff_rxn = max_vol_R_per_rxn - R_400_rxn  # Calc how much water offset to add to each rxn. (in ul)
    R_400_woff_mix = R_400_woff_rxn * R_reps * (
        1 + percent_waste - R_mix_waste_offset
    )  # Calc how much water offset to add to mix. (in ul)
    R_600_rxn = R_600 / 1000 * tot_rxn_vol / orig_R_conc  # Calc how much R primer at concentration to add. (in ul)
    R_600_mix = R_600_rxn * R_reps * (
        1 + percent_waste - R_mix_waste_offset
    )  # Calc how much R primer to add to add. (in ul)
    R_600_woff_rxn = max_vol_R_per_rxn - R_600_rxn  # Calc how much water offset to add to each rxn. (in ul)
    R_600_woff_mix = R_600_woff_rxn * R_reps * (
        1 + percent_waste - R_mix_waste_offset
    )  # Calc how much water offset to add to mix. (in ul)
    R_800_rxn = R_800 / 1000 * tot_rxn_vol / orig_R_conc  # Calc how much R primer at concentration to add. (in ul)
    R_800_mix = R_800_rxn * R_reps * (
        1 + percent_waste - R_mix_waste_offset
    )  # Calc how much R primer to add to add. (in ul)
    R_800_woff_rxn = max_vol_R_per_rxn - R_800_rxn  # Calc how much water offset to add to each rxn. (in ul)
    R_800_woff_mix = R_800_woff_rxn * R_reps * (
        1 + percent_waste - R_mix_waste_offset
    )  # Calc how much water offset to add to mix. (in ul)
    F_50_int_conc = F_50 / 1000 * tot_rxn_vol / max_vol_F_per_rxn  # What intermediate (int) concentration of F primer is needed such that by adding 1.6ul I obtain a final F primer concentration of 50, 100, 200…etc in rxn well? (in uM)
    F_100_int_conc = F_100 / 1000 * tot_rxn_vol / max_vol_F_per_rxn  # What intermediate (int) concentration of F primer is needed such that by adding 1.6ul I obtain a final F primer concentration of 50, 100, 200…etc in rxn well? (in uM)
    F_200_int_conc = F_200 / 1000 * tot_rxn_vol / max_vol_F_per_rxn  # What intermediate (int) concentration of F primer is needed such that by adding 1.6ul I obtain a final F primer concentration of 50, 100, 200…etc in rxn well? (in uM)
    F_400_int_conc = F_400 / 1000 * tot_rxn_vol / max_vol_F_per_rxn  # What intermediate (int) concentration of F primer is needed such that by adding 1.6ul I obtain a final F primer concentration of 50, 100, 200…etc in rxn well? (in uM)
    F_600_int_conc = F_600 / 1000 * tot_rxn_vol / max_vol_F_per_rxn  # What intermediate (int) concentration of F primer is needed such that by adding 1.6ul I obtain a final F primer concentration of 50, 100, 200…etc in rxn well? (in uM)
    F_800_int_conc = F_800 / 1000 * tot_rxn_vol / max_vol_F_per_rxn  # What intermediate (int) concentration of F primer is needed such that by adding 1.6ul I obtain a final F primer concentration of 50, 100, 200…etc in rxn well? (in uM)
    F_50_int_primer = F_50_int_conc * F_int_vol / orig_F_conc  # What amount of primer should be added to generate int F primer conc? (in ul)
    F_50_int_water = F_int_vol - F_50_int_primer  # What amount of water should be added to generate int F primer conc? (in ul)
    F_100_int_primer = F_100_int_conc * F_int_vol / orig_F_conc  # What amount of primer should be added to generate int F primer conc? (in ul)
    F_100_int_water = F_int_vol - F_100_int_primer  # What amount of water should be added to generate int F primer conc? (in ul)
    F_200_int_primer = F_200_int_conc * F_int_vol / orig_F_conc  # What amount of primer should be added to generate int F primer conc? (in ul)
    F_200_int_water = F_int_vol - F_200_int_primer  # What amount of water should be added to generate int F primer conc? (in ul)
    F_400_int_primer = F_400_int_conc * F_int_vol / orig_F_conc  # What amount of primer should be added to generate int F primer conc? (in ul)
    F_400_int_water = F_int_vol - F_400_int_primer  # What amount of water should be added to generate int F primer conc? (in ul)
    F_600_int_primer = F_600_int_conc * F_int_vol / orig_F_conc  # What amount of primer should be added to generate int F primer conc? (in ul)
    F_600_int_water = F_int_vol - F_600_int_primer  # What amount of water should be added to generate int F primer conc? (in ul)
    F_800_int_primer = F_800_int_conc * F_int_vol / orig_F_conc  # What amount of primer should be added to generate int F primer conc? (in ul)
    F_800_int_water = F_int_vol - F_800_int_primer  # What amount of water should be added to generate int F primer conc? (in ul)
    R_mix_rxn = bpwd_rxn + R_50_rxn + R_50_woff_rxn  # What is the rxn vol that should be aliquoted to plate wells after R primer addition? (in ul e.g.18.4)

    # more lists
    R_mix_primer = [
        R_50_mix, R_100_mix, R_200_mix, R_400_mix, R_600_mix, R_800_mix
    ]
    R_mix_water = [
        R_50_woff_mix, R_100_woff_mix, R_200_woff_mix, R_400_woff_mix,
        R_600_woff_mix, R_800_woff_mix
    ]
    F_mix_primer = [
        F_50_int_primer, F_100_int_primer, F_200_int_primer, F_400_int_primer,
        F_600_int_primer, F_800_int_primer
    ]
    F_mix_water = [
        F_50_int_water, F_100_int_water, F_200_int_water, F_400_int_water,
        F_600_int_water, F_800_int_water
    ]

    # Mixes
    BPW_mix_tot = BPW_rxn * (
        1 + percent_waste
    ) * tot_rxns  # Mix = base + probe + water (no DNA, F, R primer)*96*waste. (in ul)
    sN_mix_tot = BWP_mix_xfer_sN_mix + std_woff_add_to_sN_mix + F_add_to_sN_mix + R_add_to_sN_mix  # Mix = base + probe + water + F,R primers at std conc + water offset (no DNA) * number stds_NTC * waste
    bpwd_mix_tot = bpw_mix_xfer_bpwd_mix + std_DNA_xfer_to_bpwd_mix  # Mix = base + probe + DNA (no F, R primer)
    R_50_mix = bpwd_mix_xfer_R_mix + R_50_mix + R_50_woff_mix  # Mix = base + probe + DNA+ R primer (No F primer)
    R_100_mix = bpwd_mix_xfer_R_mix + R_100_mix + R_100_woff_mix  # Mix = base + probe + DNA+ R primer (No F primer)
    R_200_mix = bpwd_mix_xfer_R_mix + R_200_mix + R_200_woff_mix  # Mix = base + probe + DNA+ R primer (No F primer)
    R_400_mix = bpwd_mix_xfer_R_mix + R_400_mix + R_400_woff_mix  # Mix = base + probe + DNA+ R primer (No F primer)
    R_600_mix = bpwd_mix_xfer_R_mix + R_600_mix + R_600_woff_mix  # Mix = base + probe + DNA+ R primer (No F primer)
    R_800_mix = bpwd_mix_xfer_R_mix + R_800_mix + R_800_woff_mix  # Mix = base + probe + DNA+ R primer (No F primer)

    print("BWP_mix_xfer_sN_mix", BWP_mix_xfer_sN_mix)
    print("bpw_mix_xfer_bpwd_mix", bpw_mix_xfer_bpwd_mix)
    print("BWP_mix_xfer_sN_mix", BWP_mix_xfer_sN_mix)
    print("F_add_to_sN_mix", F_add_to_sN_mix)
    print("R_add_to_sN_mix", R_add_to_sN_mix)
    print("std_woff_add_to_sN_mix", std_woff_add_to_sN_mix)
    print("std_woff_per_sN_rxn", std_woff_per_sN_rxn)
    print("tot_rxn_vol", tot_rxn_vol)
    print("BPW_rxn", BPW_rxn)
    print("BPW_mix_tot", BPW_mix_tot)
    print("std_vol_F_per_rxn", std_vol_F_per_rxn)
    print("std_vol_R_per_rxn", std_vol_R_per_rxn)
    print("sN_mix_tot", sN_mix_tot)
    print("sN_mix_xfer_to_stds_mix", sN_mix_xfer_to_stds_mix)
    print("std_DNA_xfer_to_stds_mix", std_DNA_xfer_to_stds_mix)
    print("bpw_mix_xfer_bpwd_mix", bpw_mix_xfer_bpwd_mix)
    # print(split_asp(BWP_mix_xfer_sN_mix, p300_max_vol))
    # print(split_asp(bpw_mix_xfer_bpwd_mix, p300_max_vol))
    print("dna_XFR_bpwd_mix", dna_XFR_bpwd_mix)
    print("bpwd_mix_tot", bpwd_mix_tot)
    print("bpw_mix_xfer_bpwd_mix", bpw_mix_xfer_bpwd_mix)
    print("bpwd_mix_tot", bpwd_mix_tot)
    print("*" * 50)
    print("R_mix_primer", R_mix_primer)
    print("R_mix_water", R_mix_water)
    print("bpwd_mix_xfer_R_mix", bpwd_mix_xfer_R_mix)
    print("bpwd_rxn", bpwd_rxn)
    print("R_mix_rxn", R_mix_rxn)
    print("F_mix_primer", F_mix_primer)
    print("F_mix_water", F_mix_water)

    # ##### COMMANDS ######
    # prepare sN_mix
    # add BPW_mix to sN_mix tube
    p300.pick_up_tip()
    bpw_heights = tip_heights(
        BPW_mix_tot, len(split_asp(BWP_mix_xfer_sN_mix, p300_max_vol)),
        split_asp(BWP_mix_xfer_sN_mix, p300_max_vol)[0])
    p300.mix(3, 200, BPW_mix.bottom(bpw_heights[0]))
    # p300.flow_rate.aspirate = 40 #default
    # p300.flow_rate.dispense = 40 #default
    for j in range(len(split_asp(BWP_mix_xfer_sN_mix, p300_max_vol))):
        amt = split_asp(BWP_mix_xfer_sN_mix, p300_max_vol)[j]
        p300.aspirate(amt, BPW_mix.bottom(bpw_heights[j]), rate=0.4)
        protocol.delay(seconds=1)  #equilibrate
        h = tip_heights(amt + amt * j, 1, 0)[0]
        p300.dispense(amt, sN_mix.bottom(h + 5), rate=0.5)
        p300.blow_out(sN_mix.bottom(h + 10))  # want to be above liquid level
        p300.touch_tip()
    p300.drop_tip()
    # transfer water to sN__mix
    p300.transfer(
        std_woff_add_to_sN_mix,  # ~55ul
        water.bottom(5),
        sN_mix.bottom(15),  #don't want tip going too far to avoid mmix buildup
        touch_tip=True,
        blowout_location='destination well')
    # transfer F primer @ std conditions to sN__mix
    p20.transfer(F_add_to_sN_mix,
                 fwd_10uM.bottom(3),
                 sN_mix.bottom(15),
                 blow_out=True,
                 mix_after=(2, 20),
                 blowout_location='destination well')
    # transfer R primer @ std conditions to sN__mix
    p20.transfer(  #some resid fluid on outside
        R_add_to_sN_mix,
        rev_10uM.bottom(3),
        sN_mix.bottom(15),
        blow_out=True,
        mix_after=(2, 20),
        blowout_location='destination well')

    # transfer sN_mix to intermediate tubes (std_mixes)
    std_mix_heights = tip_heights(sN_mix_tot, len(std_mixes),
                                  sN_mix_xfer_to_stds_mix)  #[13,11,8,6,4,2,0]
    p300.pick_up_tip()
    # need to mix F, R and water
    p300.mix(2, 200,
             sN_mix.bottom(4))  #4mm from bottom; this algo better for mixing
    p300.mix(2, 200, sN_mix.bottom(8))  #8mm from bottom
    p300.mix(5, 200, sN_mix.bottom(std_mix_heights[0]))  #10mm from bottom
    p300.well_bottom_clearance.aspirate = std_mix_heights[0]  #mm
    for tube, h in zip(std_mixes, std_mix_heights):
        # p300.well_bottom_clearance.aspirate = h #mm
        p300.aspirate(sN_mix_xfer_to_stds_mix, sN_mix.bottom(h),
                      rate=0.4)  # 18 * 3 * 1.12-0.05= 54 + 6 =60ul
        protocol.delay(seconds=2)  #tip equilibrate
        p300.move_to(sN_mix.bottom(35))  # excess tip fluid condense
        protocol.delay(seconds=3)  #tip droplets slide
        p300.touch_tip()
        p300.dispense(sN_mix_xfer_to_stds_mix, tube, rate=0.5)
    p300.drop_tip()
    # p300.flow_rate.aspirate = 92.86 #reset to default
    # p300.flow_rate.dispense = 92.86 #reset to default
    # p300.well_bottom_clearance.aspirate = 1 #mm default

    # transfer std DNA into intermediate std_mixes tubes and then to plate
    for std, intTube, well in zip(std_tubes, std_mixes, std_wells):
        p20.pick_up_tip()
        p300.pick_up_tip()
        # p20.flow_rate.aspirate = 4
        # p20.flow_rate.dispense = 4
        p20.aspirate(
            std_DNA_xfer_to_stds_mix, std.bottom(3), rate=0.4
        )  #aspirate from std_1 into std_mix (intermediate tube) e.g. 6.42 ul
        protocol.delay(seconds=3)  #equilibrate
        p20.touch_tip()
        p20.dispense(std_DNA_xfer_to_stds_mix, intTube.bottom(2), rate=0.5)
        # p20.move_to(intTube.bottom(3))
        # p20.flow_rate.aspirate = 7.56
        # p20.flow_rate.dispense = 7.56
        p20.mix(2, 20,
                intTube.bottom(5))  #ensure vol in tip in intTube and washed
        p20.blow_out()
        p300.move_to(
            intTube.bottom(40))  #prevent tip from crashing into tube cap
        p300.mix(7, 50, intTube.bottom(1))
        protocol.delay(seconds=2)
        # p300.move_to(intTube.bottom(10)) #prevent air bubbles in mmix during blow out
        p300.blow_out(intTube.bottom(10))
        p20.move_to(intTube.bottom(40))
        for x in range(0, 3):  # need int 1, 2, and 3
            p20.aspirate(20, intTube.bottom(1), rate=0.5)
            protocol.delay(seconds=2)  #equilibrate
            # find digits in well, G1 and G10 and puts into list
            findNums = [int(i) for i in well.split()[0] if i.isdigit()]
            # joins nums from list [1, 0] -> 10 type = string
            colNum = ''.join(map(str, findNums))
            # this finds row
            row = well.split()[0][0]
            dest = row + str(int(colNum) + x)  # row + neighbor well i.e. 1, 2
            p20.dispense(20, plate[dest].bottom(2), rate=0.85)
            p20.move_to(plate[dest].bottom(5))
            p20.blow_out()
            # p20.touch_tip()
        p300.drop_tip()
        p20.drop_tip()

    # create bpwd_mix
    # First, add bpw_mix to a new tube
    p300.pick_up_tip()
    # tip_heights is a function using total_vol, # steps, and aliquot (vol decrement) amt as parameters.
    bpwd_xfer_h = tip_heights(
        BPW_mix_tot - BWP_mix_xfer_sN_mix,
        len(split_asp(bpw_mix_xfer_bpwd_mix, p300_max_vol)),
        split_asp(bpw_mix_xfer_bpwd_mix, p300_max_vol)[0])
    p300.mix(3, 200, BPW_mix.bottom(bpwd_xfer_h[0]))
    for j in range(
            len(split_asp(bpw_mix_xfer_bpwd_mix, p300_max_vol))
    ):  # split_asp is a function that returns equally divided aspirations
        amt = split_asp(bpw_mix_xfer_bpwd_mix, p300_max_vol)[j]
        p300.aspirate(amt, BPW_mix.bottom(bpwd_xfer_h[j]), rate=0.8)
        protocol.delay(seconds=2)
        h = tip_heights(amt + amt * j, 1,
                        0)[0]  # adjust tip height depending on dispenses
        p300.dispense(
            amt,
            bpwd_mix.bottom(h +
                            5))  # want tip to be just a little above dispense
        p300.blow_out(bpwd_mix.bottom(h + 8))  # want to be above liquid level
        p300.touch_tip()
    p300.drop_tip()
    # Second, add std_5 DNA or other std. 0.2ul added instead of 2ul to avoid using large volumes of std
    p20.transfer(
        dna_XFR_bpwd_mix,  #16.8ul
        std_6.bottom(3),
        bpwd_mix.bottom(24),
        mix_after=(2, dna_XFR_bpwd_mix),
        blow_out=True,
        blowout_location='destination well')
    # Third, add water to offset the reduction in DNA vol, from 2ul to 0.2 = 1.8ul*72*(1+waste-offset)
    p300.transfer(
        water_XFR_bpwd_mix,  # ~151.4ul
        water.bottom(
            20),  # vol = 900 - std_DNA_xfer_to_stds_mix (~7ul) = 893ul. 
        bpwd_mix.bottom(24))
    # Last, transfer bpwd_mix to intermediate R tubes (R_mix_1)
    bpwd_heights = tip_heights(bpwd_mix_tot, len(all_R_mix),
                               bpwd_mix_xfer_R_mix)
    bpwd_heights = tip_heights(
        BPW_mix_tot - sN_mix_tot, len(all_R_mix),
        bpwd_mix_xfer_R_mix)  #[25.9, 22.9, 19.5, 15.9, 12.3, 0.5]
    p300.pick_up_tip()
    p300.mix(2, 200,
             bpwd_mix.bottom(4))  #second to last height; for mixing at bottom
    p300.mix(2, 200, bpwd_mix.bottom(8))  #mid tip height
    p300.mix(5, 200, bpwd_mix.bottom(
        bpwd_heights[0]))  #first tip height; need thorough mix
    p300.blow_out(bpwd_mix.bottom(bpwd_heights[0] +
                                  2))  # bring tip up from solution
    # p300.flow_rate.aspirate = 30
    # p300.flow_rate.dispense = 40
    for Rtube, h in zip(all_R_mix, bpwd_heights):
        for r in range(2):
            p300.aspirate(
                bpwd_mix_xfer_R_mix / 2, bpwd_mix.bottom(h), rate=0.8
            )  # bpwd_rxn*row reps (12) * waste = 16.8*12*(1+.12-0.05)=
            protocol.delay(seconds=2)  #tip equilibrate
            p300.dispense(bpwd_mix_xfer_R_mix / 2,
                          Rtube.bottom(4 + 4 * r))  # good pos for dispense
            p300.blow_out(Rtube.bottom(10 + 6 * r))  # good pos for blow out
    p300.drop_tip()

    # add R_primer, water to all_R_mix tubes
    # add primer
    p20.transfer(
        R_mix_primer,  # list, can't do .bottom()
        rev_10uM,
        all_R_mix,  # list
        new_tip='always',
        touch_tip=True,
    )
    # add water
    p20.transfer(
        R_mix_water,  # list
        water.bottom(15),
        all_R_mix,  # list
        new_tip='always',
    )

    # mix and aliquot tubes in all_R_mix and aliquot to plate row
    for tube, row in zip(all_R_mix, plate_rows):
        p300.flow_rate.aspirate = 92.86  #reset to default
        p300.flow_rate.dispense = 92.86  #reset to default
        p300.pick_up_tip()
        # p300.move_to(tube.bottom(6))
        p300.mix(6, 200, tube.bottom(3))  # about 230ul in tube
        # p300.blow_out(tube.bottom(6))
        # p300.flow_rate.aspirate = 30
        # p300.flow_rate.dispense = 40
        for i in range(0, 2):  # split 1..12 dispensing in half
            p300.aspirate(R_mix_rxn * 2 * 3, tube.bottom(1),
                          rate=0.4)  # 18.4 *2 wells * 3 times on row
            protocol.delay(seconds=3)
            for j in range(1 + 6 * i, 6 + 6 * i,
                           2):  #1,3,5->7,9,11; distribute to every other col
                dest = row + str(j)
                p300.dispense(R_mix_rxn * 2, plate[dest],
                              rate=0.5)  # bolus for two wells
                if j == 5 or j == 11:
                    # p300.move_to(plate[dest].bottom(7)) #confirm both these work. prefer blow_out()
                    p300.blow_out(plate[dest].bottom(10))
                p300.touch_tip()
        p300.drop_tip()

    # now that PCR reactions are chillin' at 4C, make F_primer int tubes
    # Mix 100ul 'Fwd' dilutions in tube by adding water and "fwd 10uM" tube as shown in schedule
    # p20.well_bottom_clearance.aspirate=2
    # p20.well_bottom_clearance.dispense=8
    p300.transfer(F_mix_water,
                  water.bottom(12),
                  all_fwd,
                  touch_tip=True,
                  new_tip='once')

    # first two with vol < 20ul
    for first_two in range(len(F_mix_primer[0:2])):
        p20.transfer(F_mix_primer[first_two],
                     fwd_10uM.bottom(2),
                     all_fwd[first_two],
                     new_tip='once')
    # last four with vol>20
    for last_four in range(len(F_mix_primer[2:6])):
        offset = 2
        p300.transfer(
            F_mix_primer[last_four + offset],
            fwd_10uM.bottom(2),
            all_fwd[last_four + offset],
            new_tip='once'
        )  #! last well, misses aspiration, about 20ul remaining, about 50ul short. More in source tube.
    # p20.well_bottom_clearance.aspirate=1
    # p20.well_bottom_clearance.dispense=1

    # Add F_primer to wells. mix, aliquot to adjacent wells
    F_tube_heights = tip_heights(100, 1, 0)
    for i, tube in enumerate(all_fwd):
        p300.pick_up_tip()
        p20.pick_up_tip()
        # p300.flow_rate.aspirate = 92.86 #reset to default
        # p300.flow_rate.dispense = 92.86 #reset to default
        p300.mix(4, 78, tube.bottom(
            F_tube_heights[0]))  # mix F primer tube, 100ul in tube
        p300.blow_out(tube.bottom(10))
        p300.touch_tip()
        # p20.flow_rate.aspirate=4
        # p20.flow_rate.dispense=4
        p20.move_to(tube.bottom(40))
        p20.aspirate(20, tube.bottom(1),
                     rate=0.4)  # aspirate from F primer tube to wells
        p20.move_to(tube.bottom(2))  # relieve pressure if tip against tube
        protocol.delay(seconds=1)
        p20.touch_tip()
        # need 3.2ul in A1, B1, C1, D1..F1
        for x in range(0, len(plate_rows)):  # distribute to every other col
            well_pos = plate_rows[x] + plate_col[
                2 *
                i]  # var i can be used to loop through rows since each mmix is on its own row
            p20.dispense(3.2, plate[well_pos], rate=0.5)
            # protocol.delay(seconds=1)
            p20.touch_tip()
            # p20.move_to(robot.deck(['12'])) # move to trash for blow out
        p20.blow_out(liquid_trash.bottom(10))
        p20.touch_tip()  #has 20-3.2*6ul remaining; need to go in trash
        for y in range(0, len(plate_rows)):  # distribute to every other col
            well_pos = plate_rows[y] + plate_col[
                2 *
                i]  # var i can be used to loop through rows since each mmix is on its own row
            well_dest = plate_rows[y] + plate_col[2 * i + 1]
            p300.move_to(
                plate[well_pos].bottom(40))  # prevent running tip into plate
            # p300.move_to(plate[well_pos].bottom(3))
            # p300.flow_rate.aspirate = 92.86
            # p300.flow_rate.dispense = 92.86
            p300.mix(5, 20, plate[well_pos].bottom(3), rate=0.7)
            # p300.flow_rate.aspirate = 30
            # p300.flow_rate.dispense = 30
            p300.aspirate(30, plate[well_pos].bottom(3), rate=0.4)
            protocol.delay(seconds=1)
            p300.dispense(30, plate[well_pos].bottom(1),
                          rate=0.4)  #deposit slowly at bottom so no bubbles
            protocol.delay(seconds=1)
            p300.move_to(plate[well_pos].bottom(10))
            protocol.delay(seconds=2)
            # p300.flow_rate.aspirate = 92.86 # default
            # p300.flow_rate.aspirate = 92.86 # default
            p300.blow_out(plate[well_pos].bottom(15))
            p20.move_to(plate[well_pos].bottom(40))  # prevent plate collision
            p20.aspirate(20, plate[well_pos].bottom(1))
            protocol.delay(seconds=2)
            p20.dispense(20, plate[well_dest])
            p20.move_to(plate[well_dest].bottom(5))
            p20.blow_out()
            p20.touch_tip()
        p300.drop_tip()
        p20.drop_tip()
def run(ctx: protocol_api.ProtocolContext):
    ctx.comment(' ')
    ctx.comment('###############################################')
    ctx.comment('NUM SAMPLES: ' + str(NUM_SAMPLES) + ' (first 2 are controls)')
    ctx.comment('###############################################')
    ctx.comment(' ')

    # Define the STEPS of the protocol
    STEP = 0
    STEPS = {  # Dictionary with STEP activation, description, and times
        1: {
            'Execute': True,
            'description': 'Hidratate'
        },
        2: {
            'Execute': True,
            'description': 'Wait rest',
            'wait_time': 120
        },
        3: {
            'Execute': True,
            'description': 'Transfer samples'
        },
        4: {
            'Execute': True,
            'description': 'Transfer negative control'
        },
        5: {
            'Execute': True,
            'description': 'Transfer positive control'
        }
    }

    for s in STEPS:  # Create an empty wait_time
        if 'wait_time' not in STEPS[s]:
            STEPS[s]['wait_time'] = 0

    #Folder and file_path for log time
    folder_path = '/var/lib/jupyter/notebooks' + run_id
    if not ctx.is_simulating():
        if not os.path.isdir(folder_path):
            os.mkdir(folder_path)
        file_path = folder_path + '/Station_C_qPCR_time_log.txt'

    # Define Reagents as objects with their properties
    class Reagent:
        def __init__(self, name, flow_rate_aspirate, flow_rate_dispense, rinse,
                     reagent_reservoir_volume, delay, num_wells):
            self.name = name
            self.flow_rate_aspirate = flow_rate_aspirate
            self.flow_rate_dispense = flow_rate_dispense
            self.rinse = bool(rinse)
            self.reagent_reservoir_volume = reagent_reservoir_volume
            self.delay = delay
            self.num_wells = num_wells
            self.vol_well = 0
            self.unused = []
            self.vol_well_original = reagent_reservoir_volume / num_wells

    # Reagents and their characteristics
    Hydr = Reagent(name='Hydr',
                   rinse=False,
                   flow_rate_aspirate=3,
                   flow_rate_dispense=3,
                   reagent_reservoir_volume=1800,
                   num_wells=1,
                   delay=0)

    Samples = Reagent(name='Samples',
                      rinse=False,
                      flow_rate_aspirate=1,
                      flow_rate_dispense=1,
                      reagent_reservoir_volume=50,
                      delay=0,
                      num_wells=NUM_SAMPLES)

    Hydr.vol_well = Hydr.vol_well_original
    Samples.vol_well = Samples.vol_well_original

    ##################
    # Custom functions
    def divide_destinations(l, n):
        # Divide the list of destinations in size n lists.
        for i in range(0, len(l), n):
            yield l[i:i + n]

    def distribute_custom(pipette,
                          volume,
                          src,
                          dest,
                          waste_pool,
                          pickup_height,
                          extra_dispensal,
                          dest_x_offset,
                          disp_height=0):
        # Custom distribute function that allows for blow_out in different location and adjustement of touch_tip
        pipette.aspirate((len(dest) * volume) + extra_dispensal,
                         src.bottom(pickup_height))
        pipette.touch_tip(speed=20, v_offset=-5)
        pipette.move_to(src.top(z=5))
        pipette.aspirate(5)  # air gap

        for d in dest:
            pipette.dispense(5, d.top())
            drop = d.top(z=disp_height).move(Point(x=dest_x_offset))
            pipette.dispense(volume, drop)
            pipette.move_to(d.top(z=5))
            pipette.aspirate(5)  # air gap
        try:
            pipette.blow_out(waste_pool.wells()[0].bottom(pickup_height + 3))
        except:
            pipette.blow_out(waste_pool.bottom(pickup_height + 3))

        return (len(dest) * volume)

    def move_vol_multichannel(pipet, reagent, source, dest, vol, air_gap_vol,
                              x_offset, pickup_height, rinse, disp_height,
                              blow_out, touch_tip):
        '''
        x_offset: list with two values. x_offset in source and x_offset in destination i.e. [-1,1]
        pickup_height: height from bottom where volume
        rinse: if True it will do 2 rounds of aspirate and dispense before the tranfer
        disp_height: dispense height; by default it's close to the top (z=-2), but in case it is needed it can be lowered
        blow_out, touch_tip: if True they will be done after dispensing
        '''
        # Rinse before aspirating
        if rinse == True:
            custom_mix(pipet,
                       reagent,
                       location=source,
                       vol=vol,
                       rounds=2,
                       blow_out=True,
                       mix_height=0,
                       x_offset=x_offset)

        # SOURCE
        s = source.bottom(pickup_height).move(Point(x=x_offset[0]))
        pipet.aspirate(vol, s)  # aspirate liquid
        if air_gap_vol != 0:  # If there is air_gap_vol, switch pipette to slow speed
            pipet.aspirate(air_gap_vol,
                           source.top(z=-2),
                           rate=reagent.flow_rate_aspirate)  # air gap

        # GO TO DESTINATION
        drop = dest.top(z=disp_height).move(Point(x=x_offset[1]))
        pipet.dispense(vol + air_gap_vol,
                       drop,
                       rate=reagent.flow_rate_dispense)  # dispense all

        ctx.delay(
            seconds=reagent.delay)  # pause for x seconds depending on reagent

        if blow_out == True:
            pipet.blow_out(dest.top(z=-2))
        if touch_tip == True:
            pipet.touch_tip(speed=20, v_offset=-5, radius=0.5)

    def custom_mix(pipet,
                   reagent,
                   location,
                   vol,
                   rounds,
                   blow_out,
                   mix_height,
                   x_offset,
                   source_height=3):
        '''
        Function for mixing a given [vol] in the same [location] a x number of [rounds].
        blow_out: Blow out optional [True,False]
        x_offset = [source, destination]
        source_height: height from bottom to aspirate
        mix_height: height from bottom to dispense
        '''
        if mix_height <= 0:
            mix_height = 3

        pipet.aspirate(1,
                       location=location.bottom(z=source_height).move(
                           Point(x=x_offset[0])),
                       rate=reagent.flow_rate_aspirate)

        for _ in range(rounds):
            pipet.aspirate(vol,
                           location=location.bottom(z=source_height).move(
                               Point(x=x_offset[0])),
                           rate=reagent.flow_rate_aspirate)
            pipet.dispense(vol,
                           location=location.bottom(z=mix_height).move(
                               Point(x=x_offset[1])),
                           rate=reagent.flow_rate_dispense)

        pipet.dispense(1,
                       location=location.bottom(z=mix_height).move(
                           Point(x=x_offset[1])),
                       rate=reagent.flow_rate_dispense)

        if blow_out == True:
            pipet.blow_out(location.top(z=-2))  # Blow out

    ####################################
    # load labware and modules
    # 24 well rack
    tuberack = ctx.load_labware(
        'opentrons_24_aluminumblock_generic_2ml_screwcap', '2',
        'Opentrons 24 Well Aluminum Block with Generic 2 mL Screwcap')

    ############################################
    # tempdecks
    tempdeck_orig = ctx.load_module('Temperature Module Gen2', '4')
    tempdeck_dest = ctx.load_module('Temperature Module Gen2', '1')

    if SET_TEMP_ON_SLOT_4:
        tempdeck_orig.set_temperature(TEMPERATURE_SLOT_4)
    if SET_TEMP_ON_SLOT_1:
        tempdeck_dest.set_temperature(TEMPERATURE_SLOT_1)

    ##################################
    # Sample plate - comes from B
    source_plate = tempdeck_orig.load_labware(
        'kingfisher_96_aluminumblock_200ul',
        'Kingfisher 96 Aluminum Block 200 uL')

    ##################################
    # qPCR plate - final plate, goes to PCR
    qpcr_plate = tempdeck_dest.load_labware(
        'opentrons_96_aluminumblock_generic_pcr_strip_200ul',
        'Opentrons 96 Well Aluminum Block with Generic PCR Strip 200 µL')

    ##################################
    # Load Tipracks
    tips20 = [
        ctx.load_labware('opentrons_96_filtertiprack_20ul', slot)
        for slot in ['5']
    ]

    tips200 = [
        ctx.load_labware('opentrons_96_filtertiprack_200ul', slot)
        for slot in ['3']
    ]

    ################################################################################
    # Declare which reagents are in each reservoir as well as deepwell and elution plate
    Hydr.reagent_reservoir = tuberack.rows()[0][0]  # A1

    # setup up sample sources and destinations
    samples = source_plate.wells()[2:NUM_SAMPLES]
    pcr_wells = qpcr_plate.wells()[:NUM_SAMPLES]
    pcr_wells_samples = qpcr_plate.wells()[2:NUM_SAMPLES]

    # Divide destination wells in small groups for P300 pipette
    dests = list(divide_destinations(pcr_wells, size_transfer))

    # pipettes
    p20 = ctx.load_instrument('p20_single_gen2',
                              mount='right',
                              tip_racks=tips20)
    p300 = ctx.load_instrument('p300_single_gen2',
                               mount='left',
                               tip_racks=tips200)

    # used tip counter and set maximum tips available
    tip_track = {
        'counts': {
            p300: 0,
            p20: 0
        },
        'maxes': {
            p300: 96 * len(p300.tip_racks),
            p20: 96 * len(p20.tip_racks)
        }
    }

    ##########
    # pick up tip and if there is none left, prompt user for a new rack
    def pick_up(pip):
        nonlocal tip_track
        if not ctx.is_simulating():
            if tip_track['counts'][pip] == tip_track['maxes'][pip]:
                ctx.pause('Replace ' + str(pip.max_volume) +
                          'µl tipracks before \
                resuming.')
                pip.reset_tipracks()
                tip_track['counts'][pip] = 0

        if not pip.hw_pipette['has_tip']:
            pip.pick_up_tip()

    ##########

    ############################################################################
    # STEP 1: HIDRATATE
    ############################################################################
    STEP += 1
    if STEPS[STEP]['Execute'] == True:
        start = datetime.now()
        ctx.comment(' ')
        ctx.comment('###############################################')
        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'])
        ctx.comment('###############################################')
        ctx.comment(' ')

        pick_up(p300)
        used_vol = []

        for dest in dests:
            aspirate_volume = HYDR_VOL_PER_SAMPLE * len(dest) + extra_dispensal
            used_vol_temp = distribute_custom(
                p300,
                volume=HYDR_VOL_PER_SAMPLE,
                src=Hydr.reagent_reservoir,
                dest=dest,
                waste_pool=Hydr.reagent_reservoir,
                pickup_height=0.2,
                extra_dispensal=extra_dispensal,
                dest_x_offset=2,
                disp_height=-1)
            used_vol.append(used_vol_temp)

        p300.drop_tip(home_after=False)
        tip_track['counts'][p300] += 1

        end = datetime.now()
        time_taken = (end - start)
        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'] +
                    ' took ' + str(time_taken))
        STEPS[STEP]['Time:'] = str(time_taken)

    ###############################################################################
    # STEP 2 WAIT REST
    ########
    STEP += 1
    if STEPS[STEP]['Execute'] == True:
        start = datetime.now()
        ctx.comment(' ')
        ctx.comment('###############################################')
        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'])
        ctx.comment('###############################################')
        ctx.comment(' ')

        ctx.comment(' ')
        ctx.delay(seconds=STEPS[STEP]['wait_time'],
                  msg='Wait for ' + format(STEPS[STEP]['wait_time']) +
                  ' seconds.')
        ctx.comment(' ')

        end = datetime.now()
        time_taken = (end - start)
        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'] +
                    ' took ' + str(time_taken))
        STEPS[STEP]['Time:'] = str(time_taken)
        ctx.comment('Used tips in total: ' + str(tip_track['counts'][p300]))

    ############################################################################
    # STEP 3: TRANSFER SAMPLES
    ############################################################################
    STEP += 1
    if STEPS[STEP]['Execute'] == True:
        start = datetime.now()
        ctx.comment(' ')
        ctx.comment('###############################################')
        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'])
        ctx.comment('###############################################')
        ctx.comment(' ')

        for s, d in zip(samples, pcr_wells_samples):
            pick_up(p20)

            move_vol_multichannel(p20,
                                  reagent=Samples,
                                  source=s,
                                  dest=d,
                                  vol=VOLUME_SAMPLE,
                                  air_gap_vol=air_gap_sample,
                                  x_offset=x_offset,
                                  pickup_height=0.2,
                                  disp_height=0,
                                  rinse=False,
                                  blow_out=True,
                                  touch_tip=True)
            p20.drop_tip(home_after=False)
            tip_track['counts'][p20] += 1

        end = datetime.now()
        time_taken = (end - start)
        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'] +
                    ' took ' + str(time_taken))
        STEPS[STEP]['Time:'] = str(time_taken)

    ############################################################################
    # STEP 4: TRANSFER NEGATIVE CONTROL
    ############################################################################
    STEP += 1
    if STEPS[STEP]['Execute'] == True:
        start = datetime.now()
        ctx.comment(' ')
        ctx.comment('###############################################')
        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'])
        ctx.comment('###############################################')
        ctx.comment(' ')

        pick_up(p20)

        s = tuberack.rows()[0][1]  # A2
        d = qpcr_plate.wells()[1]  # B1
        move_vol_multichannel(p20,
                              reagent=Samples,
                              source=s,
                              dest=d,
                              vol=VOLUME_SAMPLE,
                              air_gap_vol=air_gap_sample,
                              x_offset=x_offset,
                              pickup_height=0.2,
                              disp_height=0,
                              rinse=False,
                              blow_out=True,
                              touch_tip=True)

        p20.drop_tip(home_after=False)
        tip_track['counts'][p20] += 1

        end = datetime.now()
        time_taken = (end - start)
        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'] +
                    ' took ' + str(time_taken))
        STEPS[STEP]['Time:'] = str(time_taken)

    ############################################################################
    # STEP 5: TRANSFER POSITIVE CONTROL
    ############################################################################
    STEP += 1
    if STEPS[STEP]['Execute'] == True:
        start = datetime.now()
        ctx.comment(' ')
        ctx.comment('###############################################')
        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'])
        ctx.comment('###############################################')
        ctx.comment(' ')

        pick_up(p20)

        s = tuberack.rows()[0][2]  # A3
        d = qpcr_plate.wells()[0]  # A1
        move_vol_multichannel(p20,
                              reagent=Samples,
                              source=s,
                              dest=d,
                              vol=VOLUME_SAMPLE,
                              air_gap_vol=air_gap_sample,
                              x_offset=x_offset,
                              pickup_height=0.2,
                              disp_height=0,
                              rinse=False,
                              blow_out=True,
                              touch_tip=True)

        p20.drop_tip(home_after=False)
        tip_track['counts'][p20] += 1

        end = datetime.now()
        time_taken = (end - start)
        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'] +
                    ' took ' + str(time_taken))
        STEPS[STEP]['Time:'] = str(time_taken)

    # Export the time log to a tsv file
    if not ctx.is_simulating():
        with open(file_path, 'w') as f:
            f.write(
                'STEP\texecution\tdescription\twait_time\texecution_time\n')
            for key in STEPS.keys():
                row = str(key)
                for key2 in STEPS[key].keys():
                    row += '\t' + format(STEPS[key][key2])
                f.write(row + '\n')
        f.close()

    ############################################################################
    # Light flash end of program
    for i in range(3):
        #ctx._hw_manager.hardware.set_lights(rails=False)
        ctx._hw_manager.hardware.set_lights(button=(1, 0, 0))
        time.sleep(0.3)
        #ctx._hw_manager.hardware.set_lights(rails=True)
        ctx._hw_manager.hardware.set_lights(button=(0, 0, 1))
        time.sleep(0.3)
    ctx._hw_manager.hardware.set_lights(button=(0, 1, 0))
    ctx.comment('Finished! \nMove plate to PCR')

    total_used_vol = np.sum(used_vol)
    total_needed_volume = total_used_vol
    ctx.comment('Total Hydr used volume is: ' + str(total_used_vol) +
                '\u03BCl.')
    ctx.comment('Needed Hydr volume is ' +
                str(total_needed_volume + extra_dispensal * len(dests)) +
                '\u03BCl')
    ctx.comment('Hydr remaining in tubes is: ' + format(
        np.sum(Hydr.unused) + extra_dispensal * len(dests) + Hydr.vol_well) +
                '\u03BCl.')
    ctx.comment('200 ul Used tips in total: ' + str(tip_track['counts'][p300]))
    ctx.comment('200 ul Used racks in total: ' +
                str(tip_track['counts'][p300] / 96))
    ctx.comment('20 ul Used tips in total: ' + str(tip_track['counts'][p20]))
    ctx.comment('20 ul Used racks in total: ' +
                str(tip_track['counts'][p20] / 96))
Example #17
0
def run(protocol: protocol_api.ProtocolContext):
    # labware
    plate_stock = protocol.load_labware('cornering_96_wellplate_500ul', '9')
    plate_dna = protocol.load_labware('nunc_96_ubottom', '6')
    plate_nuc = protocol.load_labware('lonza_96_electroporation', '3')
    trough = protocol.load_labware('axygen_12_reservior_22ml', '8')
    tip200_1 = protocol.load_labware('opentrons_96_filtertiprack_200ul', '7')
    tip200_2 = protocol.load_labware('opentrons_96_filtertiprack_200ul', '10')
    tip200_3 = protocol.load_labware('opentrons_96_filtertiprack_200ul', '11')

    plate24_1A = protocol.load_labware('nunc_24_pseudo_a', '1')
    plate24_2B = protocol.load_labware('nunc_24_pseudo_b', '2')
    plate24_3A = protocol.load_labware('nunc_24_pseudo_a', '4')
    plate24_4B = protocol.load_labware('nunc_24_pseudo_b', '5')

    # pipettes (& settings if different to defaults)
    p300m = protocol.load_instrument('p300_multi',
                                     mount='right',
                                     tip_racks=[tip200_1, tip200_2])
    p300m.flow_rate.aspirate = 100
    p300m.flow_rate.dispense = 200
    p300m.maximum_volume = 200
    p300m.minimum_volume = 15

    p50m = protocol.load_instrument('p50_multi',
                                    mount='left',
                                    tip_racks=[tip200_1, tip200_3])

    #Step 1: Distrubute Nuc Solution to DNA plate
    p50m.pick_up_tip()
    for i in range(4):
        p50m.aspirate(45, trough.wells()[0])
        p50m.dispense(38, plate_dna.wells()[8 * i])
        protocol.delay(seconds=1)
        p50m.blow_out(trough.wells()[0].top())
    p50m.drop_tip()

    #Step 2: Distrubute DNA/RNA mix to DNA Plate
    for i in range(4):
        p50m.pick_up_tip()
        p50m.mix(3, 50, plate_stock.wells()[8 * i])
        protocol.delay(seconds=1)
        p50m.blow_out(plate_stock.wells()[8 * i].top())
        p50m.transfer(7,
                      plate_stock.columns()[i],
                      plate_dna.columns()[i],
                      mix_after=(1, 40),
                      new_tip='never')
        protocol.delay(seconds=1)
        p50m.blow_out(plate_dna.wells()[8 * i].top())
        p50m.drop_tip()

    # Intervention 1: Insert pause to comfirm cells ready in trough column 2
    protocol.pause()
    protocol.comment(
        'ATTENTION: Ensure below criteris are met prior to resuming protocol. Resuspended cells added to trough, position 8, column 2. Once complete click resume'
    )

    #Step 3: Mix cells + transfer to DNA plate
    p300m.pick_up_tip()
    p300m.well_bottom_clearance.aspirate = 2
    p300m.well_bottom_clearance.dispense = 10
    for j in range(15):
        p300m.aspirate(190, trough.wells_by_name()['A2'], rate=3.0)
        p300m.dispense(190, trough.wells_by_name()['A2'], rate=3.0)
    protocol.delay(seconds=1)
    p300m.blow_out(trough.wells_by_name()['A2'].top())
    p300m.touch_tip()
    p300m.drop_tip()
    p300m.flow_rate.aspirate = 150
    p300m.flow_rate.dispense = 200
    p300m.well_bottom_clearance.aspirate = 1
    p300m.well_bottom_clearance.dispense = 1

    for i in range(4):
        p50m.pick_up_tip()
        p50m.well_bottom_clearance.aspirate = 2
        p50m.well_bottom_clearance.dispense = 10
        for j in range(5):
            p50m.aspirate(50, trough.wells_by_name()['A2'], rate=5.0)
            p50m.dispense(50, trough.wells_by_name()['A2'], rate=5.0)
        p50m.well_bottom_clearance.aspirate = 1
        p50m.well_bottom_clearance.dispense = 1
        protocol.delay(seconds=1)
        p50m.blow_out(trough.wells_by_name()['A2'].top())
        p50m.transfer(45,
                      trough.wells('A2'),
                      plate_dna.wells()[8 * i],
                      new_tip='never',
                      mix_after=(2, 50),
                      touch_tip=True)
        protocol.delay(seconds=1)
        p50m.blow_out(plate_dna.wells()[8 * i])
        p50m.drop_tip()

    #Step 4: Distribute cells to nucleofection plate
    for i in range(4):  # loop for 4 columns on DNA setup plate
        p50m.pick_up_tip()
        p50m.mix(10, 50, plate_dna.wells()[8 * i], rate=5.0)
        protocol.delay(seconds=1)
        p50m.blow_out(plate_dna.wells()[8 * i].top())
        for j in range(3):  # Subloop for 3 replicates
            p50m.mix(4, (50 - 10 * j), plate_dna.wells()[8 * i], rate=5.0)
            p50m.blow_out(plate_dna.wells()[8 * i].top())
            protocol.delay(seconds=1.0)
            p50m.well_bottom_clearance.dispense = 2.5
            p50m.aspirate(25, plate_dna.wells()[8 * i])
            p50m.dispense(20, plate_nuc.wells()[8 * (3 * i + j)])
            protocol.delay(seconds=1.5)
            p50m.well_bottom_clearance.dispense = 1
            p50m.blow_out(plate_dna.wells()[8 * i].top())
        p50m.drop_tip()

    #Intervention 3: Insert pause for electroporation
    protocol.pause()
    protocol.comment(
        'ATTENTION: Ensure below criteris are met prior to resuming protocol. Perform electroporation and return nucleofection plate to position 3. During electroporation, add pregassed media to trough, position 8, col 3. Once complete click resume.'
    )

    #Step 5: Add 80ul media to all wells
    p300m.well_bottom_clearance.dispense = 12
    p300m.pick_up_tip()
    for i in range(12):
        p300m.aspirate(80, trough.wells()[2])
        p300m.dispense(80, plate_nuc.wells()[8 * i])
        protocol.delay(seconds=1)
        p300m.blow_out(plate_nuc.wells()[8 * i].top())
    p300m.drop_tip()
    p300m.well_bottom_clearance.dispense = 1
    protocol.home()

    #Intervention 4: Reset tipracks for seeding
    protocol.pause()
    protocol.comment(
        'ATTENTION: Ensure below criteria are met prior to resuming protocol. Please reset tipracks as detailed below ready for seeding of cells. tip200_1 (slot 7) Only odd rows or tips. tip200_2 (slot 10) requires only even rows of tips. Extended details in ReadME section of script. Once complete click resume.'
    )
    p300m.reset_tipracks()  # Reset tipracks

    #Step 8: Seed into 24SWPs
    List_plate = [(0, plate24_1A, tip200_1), (0, plate24_2B, tip200_2),
                  (6, plate24_3A, tip200_1), (6, plate24_4B, tip200_2)]
    #In list arguments 1-4 are: 24SWP number, 24SWP name, tiprack, column offset adjuster

    for (j, plate24, tip), i in product(
            List_plate, range(6)
    ):  #'produt' multiplies two variables into a matrix, same as doubble loop.
        isource = plate24.wells()[4 * (
            i
        )]  #isource and isource 2 are the same location, defined by wells or columns
        idest_nuc = plate_nuc.wells()[8 * (i + j)]

        p300m.well_bottom_clearance.aspirate = 2.5
        p300m.well_bottom_clearance.dispense = 2.5
        p300m.pick_up_tip(tip['A' + str(i + j + 1)])
        for m in range(10):
            p300m.aspirate(70, idest_nuc, rate=2.0)
            p300m.dispense(70, idest_nuc, rate=2.0)
        protocol.delay(seconds=1.0)
        p300m.blow_out(plate_nuc.wells()[8 * (j + i)].top())
        protocol.delay(seconds=1.0)
        p300m.aspirate(70, idest_nuc, rate=0.5)
        p300m.well_bottom_clearance.aspirate = 1.0
        p300m.well_bottom_clearance.dispense = 1.0
        p300m.dispense(70, isource)
        p300m.mix(2, 190, isource)
        protocol.delay(seconds=1.0)
        p300m.blow_out(isource.top())
        p300m.drop_tip()
Example #18
0
def run(ctx: protocol_api.ProtocolContext):

    [csv, m300_mount, p300_mount, temp_mod_temp, asp_rate_step1,
     pbs_dispense_rate,
     incubation_time, first_media_x, second_media_y, track_tips
     ] = get_values(  # noqa: F821
        "csv", "m300_mount", "p300_mount", "temp_mod_temp",
        "asp_rate_step1", "pbs_dispense_rate",
        "incubation_time", "first_media_x", "second_media_y", "track_tips")

    # LABWARE
    temp_mod = ctx.load_module('temperature module gen2', '10')
    reagents = ctx.load_labware('nest_12_reservoir_15ml', '11')
    waste_res = ctx.load_labware('nest_12_reservoir_15ml', '7')
    plate = temp_mod.load_labware(
                'corning_96_wellplate_360ul_flat', '10')

    # TIPRACKS
    tipracks = [ctx.load_labware('opentrons_96_filtertiprack_200ul', slot)
                for slot in ['4', '5', '6']]

    # INSTRUMENTS
    p300 = ctx.load_instrument('p300_single_gen2',
                               p300_mount,
                               tip_racks=tipracks)
    m300 = ctx.load_instrument('p300_multi_gen2',
                               m300_mount,
                               tip_racks=tipracks)

    tips_by_col = [tip for rack in tipracks
                   for col in rack.columns() for tip in col[::-1]]
    tip_cols = [tips_by_col[i:i+8] for i in range(0, len(tips_by_col), 8)]

    """ TIP-TRACKING BETWEEN RUNS. """
    total_tip_cols = 36

    file_path = '/data/csv/tiptracking.json'
    file_dir = os.path.dirname(file_path)

    tips_by_col = [tip for rack in tipracks
                   for col in rack.columns() for tip in col[::-1]]
    tip_cols = [tips_by_col[i:i+8] for i in range(0, len(tips_by_col), 8)]

    if track_tips and not ctx.is_simulating():
        # check for file directory
        if not os.path.exists(file_dir):
            os.makedirs(file_dir)
        # if no file, then use standard tip_chunks definition, and the
        # end of the code will write to updated tip_chunks list to
        # the file created. This if statement handles the case in which
        # tip tracking is selected for the first time.
        if not os.path.isfile(file_path):
            tip_chunks = [tips_by_col[i:i+8] for i in range(0,
                          len(tips_by_col), 8)]
        else:
            # grab nested list tip_chunks from file.
            source = open(file_path, 'rb').read()
            # see below for conversion of tip_chunks nested list to bools.
            # in order to dump the well objects in tip_chunks to a json file,
            # they had to be serializable (int, string, bool). The end of the
            # protocol does this conversion.
            tip_bool_chunks = json.loads(source)

            # convert bools back to well objects to use.
            tip_chunks = [[] for _ in range(total_tip_cols)]
            for i, (bool_chunk, tip_chunk) in enumerate(zip(tip_bool_chunks,
                                                            tip_cols)):
                if len(bool_chunk) == 0:
                    continue
                for true_tip, tip_loc in zip(bool_chunk, tip_chunk):
                    if true_tip:
                        tip_chunks[i].append(tip_loc)
                    else:
                        continue

    else:
        # standard definition of tip_chunks if not tracking tips.
        tip_chunks = [tips_by_col[i:i+8] for i in range(0,
                      len(tips_by_col), 8)]
    """PROTOCOL BEGINS """
    csv_rows = [[val.strip() for val in line.split(',')]
                for line in csv.splitlines()
                if line.split(',')[0].strip()][1:]

    """FIND INVOLVED WELLS"""
    values_from_csv = []
    wells_from_csv = []
    for row in csv_rows:
        well, value = row[:2]
        value = int(value)
        values_from_csv.append(value)
        wells_from_csv.append(well)

    # create nested list of all values in csv (by column).
    value_chunk_cols = [values_from_csv[i:i+8]
                        for i in range(0, len(values_from_csv), 8)]
    list_well_tips = []

    """CREATE A LIST OF # TIPS FOR EACH WELL"""
    start_point = 0
    tip_count = 0
    for i, chunk in enumerate(value_chunk_cols):
        start_point = 0

        # check for the values in each column.
        # if we find a well with a value of 85 or greater,
        # use that index (j) as the starting point and see how many values
        # after that are also greater than 85. Once we don't find one,
        # break.
        for j, value in enumerate(chunk[start_point:]):
            if value >= 85:
                for check_values in chunk[j:]:
                    if check_values >= 85:
                        tip_count += 1
                    else:
                        break

                list_well_tips.append(tip_count)
                tip_count = 0
                continue

            else:
                list_well_tips.append(0)

    # create a dictionary which says how many tips go to each well.
    # For example, if the entire first column has values higher than 85,
    # the first value in the dictionary will be "A1: 8". If first four wells
    # in column 2 are greater than 85, "B1:4".
    dict_tips_per_well = {}
    tip_ctr = 0
    for j, (well, num_tips) in enumerate(zip(wells_from_csv,
                                             list_well_tips)):
        if tip_ctr > 0:
            tip_ctr -= 1
            continue

        if num_tips > 0:
            tip_ctr = num_tips - 1
            dict_tips_per_well[well] = num_tips

    # print('\n\n', dict_tips_per_well, '\n\n')

    """PICKUP FUNCTION"""
    def pick_up(num_channels_per_pickup):
        nonlocal tip_chunks
        if num_channels_per_pickup > 1:
            pip = m300
        else:
            pip = p300
        try:
            col = 0
            # based on the demand of the next well (1-8 tips), this for loop
            # will find the first available column having adequate number
            # of tips starting from the first. If the tip pick up order is:
            # 6, 8, 2 for the first 3 pick ups, then 6 tips will be taken from
            # column 1, 8 tips from column 2, and 2 tips back from column 1.
            # efficient tip pick up instead of "throwing away" a whole column
            # after pick up.
            for _ in range(36):
                if num_channels_per_pickup <= len(tip_chunks[col]):
                    break
                else:
                    col += 1
            pip.pick_up_tip(tip_chunks[col][num_channels_per_pickup-1])

            # remove as many tips as we picked up in that column
            # from the 0 index.
            for _ in range(num_channels_per_pickup):
                tip_chunks[col].pop(0)

        # replace tip exception
        except IndexError:
            ctx.pause("Replace empty tip racks on slots 4, 5, and 6")
            pip.reset_tipracks()
            tip_chunks = [tips_by_col[i:i+8] for i in range(0,
                          len(tips_by_col), 8)]
            col = 0
            for _ in range(36):
                if num_channels_per_pickup <= len(tip_chunks[col]):
                    break
                else:
                    col += 1

            pip.pick_up_tip(tip_chunks[col][num_channels_per_pickup-1])

            for _ in range(num_channels_per_pickup):
                tip_chunks[col].pop(0)

                if len(tip_chunks[col]) == 0:
                    tip_chunks.remove(tip_chunks[col])

    # DUMP WASTE
    vol_ctr = 0
    waste_well = 0

    # move to next well in reservoir once we fill one.
    def check_waste_vol(vol):
        nonlocal vol_ctr
        nonlocal waste_well
        vol_ctr += vol
        if vol_ctr > 12000:
            waste_well += 1
            vol_ctr = 0
    waste = waste_res.wells()[waste_well]
    temp_mod.set_temperature(temp_mod_temp)

    ctx.pause("""
    Ensure temperature module is at correct temperature, then,
    select "Resume" on the Opentrons app.
    """)

    # REAGENTS
    pbs = reagents.wells()[0]
    trypsin = reagents.wells()[1]
    media = reagents.wells()[-1]

    airgap = 20

    ctx.comment("MOVING INCLUDED WELLS TO WASTE")
    for i, well in enumerate(dict_tips_per_well):
        num_tips = dict_tips_per_well[well]
        plate_well = plate.wells_by_name()[well]
        if num_tips > 1:
            pip = m300
        else:
            pip = p300

        pick_up(num_tips)
        # aspirate from side so as to not disturb cell culture.
        pip.aspirate(200, plate_well.bottom(z=1).move(
                Point(x=(plate_well.diameter/2-2))), rate=asp_rate_step1)
        pip.dispense(200, waste)
        check_waste_vol(200)
        pip.air_gap(airgap)
        pip.drop_tip()
        ctx.comment('\n')
    ctx.comment("\n\n\nMOVING PBS TO PLATE")
    for i, well in enumerate(dict_tips_per_well):
        num_tips = dict_tips_per_well[well]
        plate_well = plate.wells_by_name()[well]
        if num_tips > 1:
            pip = m300
        else:
            pip = p300

        pick_up(num_tips)
        pip.aspirate(150, pbs, rate=pbs_dispense_rate)
        pip.dispense(150, plate_well.bottom(z=1).move(
                Point(x=(plate_well.diameter/2-2))))
        pip.air_gap(airgap)
        pip.drop_tip()
        ctx.comment('\n')

    ctx.comment("\n\n\nREMOVING PBS FROM PLATE")
    for i, well in enumerate(dict_tips_per_well):
        num_tips = dict_tips_per_well[well]
        plate_well = plate.wells_by_name()[well]
        if num_tips > 1:
            pip = m300
        else:
            pip = p300

        pick_up(num_tips)
        pip.aspirate(175, plate_well.bottom(z=1).move(
                Point(x=(plate_well.diameter/2-2))))
        pip.dispense(175, waste)
        pip.air_gap(airgap)
        pip.drop_tip()
        ctx.comment('\n')

    ctx.comment("\n\n\nMOVING TRYPSIN TO PLATE")
    for i, well in enumerate(dict_tips_per_well):

        num_tips = dict_tips_per_well[well]
        plate_well = plate.wells_by_name()[well]
        if num_tips > 1:
            pip = m300
        else:
            pip = p300

        pick_up(num_tips)
        pip.aspirate(25, trypsin)
        pip.dispense(25, plate_well)
        pip.blow_out()
        pip.touch_tip()
        pip.air_gap(airgap)
        pip.drop_tip()
        ctx.comment('\n')

    ctx.delay(minutes=incubation_time)

    ctx.comment("\n\n\nMOVING MEDIA TO PLATE")
    for i, well in enumerate(dict_tips_per_well):

        num_tips = dict_tips_per_well[well]
        plate_well = plate.wells_by_name()[well]
        if num_tips > 1:
            pip = m300
        else:
            pip = p300

        pick_up(num_tips)
        pip.aspirate(140, media)
        pip.dispense(140, plate_well)
        pip.blow_out()
        pip.touch_tip()
        pip.air_gap(airgap)
        pip.drop_tip()
        ctx.comment('\n')

    ctx.comment("\n\n\nASPIRATE FIRST MEDIA FROM PLATE")
    for i, well in enumerate(dict_tips_per_well):

        num_tips = dict_tips_per_well[well]
        plate_well = plate.wells_by_name()[well]
        if num_tips > 1:
            pip = m300
        else:
            pip = p300

        pick_up(num_tips)
        pip.aspirate(first_media_x, plate_well.bottom(z=1).move(
                Point(x=(plate_well.diameter/2-2))))
        pip.dispense(first_media_x, waste)
        pip.air_gap(airgap)
        pip.drop_tip()
        ctx.comment('\n')

    ctx.comment("\n\n\nDISPENSE SECOND MEDIA TO PLATE")
    for i, well in enumerate(dict_tips_per_well):

        num_tips = dict_tips_per_well[well]
        plate_well = plate.wells_by_name()[well]
        if num_tips > 1:
            pip = m300
        else:
            pip = p300

        pick_up(num_tips)
        pip.aspirate(second_media_y, media)
        pip.dispense(second_media_y, plate_well)
        pip.air_gap(airgap)
        pip.drop_tip()
        ctx.comment('\n')

    tip_data = []
    for i, chunk in enumerate(tip_chunks):
        tip_data.append([])
        if len(chunk) > 0:
            for value in chunk:
                tip_data[i].append(True)
        else:
            continue

    # write to the ot-2 no matter what in case the user would like to start
    # tracking tips for the next run
    if not ctx.is_simulating():
        with open(file_path, 'w') as outfile:
            outfile.write(json.dumps(tip_data))
Example #19
0
def run(ctx: protocol_api.ProtocolContext):
    [
        mag_engage_time, n_samples, left_pipette_lname, right_pipette_lname,
        left_pipette_tipracks_lname, right_pipette_tipracks_lname,
        reservoir_lname, destination_plate_lname, sample_plate_lname,
        mag_mod_lname, tube_rack_lname, dest_temp_mod_lname, do_vortex_pause,
        do_SDS_step, do_DNAse_step, use_NaCl, bead_volume, wash_buf_vol,
        elution_buf_vol, n_washes, n_wash_mixes, n_elution_mixes,
        incubation_time, n_bead_mixes, sds_buffer_vol, starting_volume
    ] = get_values(  # noqa: F821 (<--- DO NOT REMOVE!)
        "mag_engage_time", "n_samples", "left_pipette_lname",
        "right_pipette_lname", "left_pipette_tipracks_lname",
        "right_pipette_tipracks_lname", "reservoir_lname",
        "destination_plate_lname", "sample_plate_lname", "mag_mod_lname",
        "tube_rack_lname", "dest_temp_mod_lname", "do_vortex_pause",
        "do_SDS_step", "do_DNAse_step", "use_NaCl", "bead_volume",
        "wash_buf_vol", "elution_buf_vol", "n_washes", "n_wash_mixes",
        "n_elution_mixes", "incubation_time", "n_bead_mixes", "sds_buffer_vol",
        "starting_volume")

    # define all custom variables above here with descriptions:

    # Calculate reagent volumes
    # See docs for calculations
    # 10:1, v_lysis = v_s/9, e.g. for v_s = 1000 uL, v_lysis = 1000/9=111 uL
    lysis_buffer_vol = starting_volume / 9
    dnaseI_vol = starting_volume / 1000  # 1 uL per mL
    total_lysis_vol = starting_volume + lysis_buffer_vol + dnaseI_vol

    nacl_first_step_vol = total_lysis_vol / 7
    nacl_wash_buf_vol = wash_buf_vol / 7

    total_vol_after_bead_adddn = round(total_lysis_vol + bead_volume, 1)
    if use_NaCl:
        total_vol_after_bead_adddn = round(
            total_vol_after_bead_adddn + nacl_first_step_vol, 1)

    n_columns = math.ceil(n_samples / 8)

    # Error checking
    # If DNAse I is being added from a tube we need to make sure that
    # a) we have a single pipette loaded and b) that dnaseI_vol > pipette min.
    # volume
    if (("single" not in left_pipette_lname
         and "single" not in right_pipette_lname) and do_DNAse_step):
        raise Exception("No single channel pipette for DNAse I distribution " +
                        "selected")
    # More error checking on this in the pipette loading section

    # load modules
    '''

    Add your modules here with:

    module_name = ctx.load_module('{module_loadname}', '{slot number}')

    Note: if you are loading a thermocycler, you do not need to specify
    a slot number - thermocyclers will always occupy slots 7, 8, 10, and 11.

    For all other modules, you can load them on slots 1, 3, 4, 6, 7, 9, 10.

    '''
    # Load temperature modules (if any)
    dest_temp_mod = None
    if dest_temp_mod_lname:
        dest_temp_mod = ctx.load_module(dest_temp_mod_lname, '4')

    # Load the magnetic module
    mag_mod = ctx.load_module(mag_mod_lname, '1')

    # Load labware
    sample_plate = mag_mod.load_labware(sample_plate_lname)

    sample_well = sample_plate.wells()[0]
    if total_vol_after_bead_adddn > sample_well.max_volume:
        raise Exception("The sample wells are too small to handle the " +
                        "volumes of reagents")

    reservoir = ctx.load_labware(reservoir_lname, '7')

    dnaseI_tuberack = None
    if do_DNAse_step:
        dnaseI_tuberack = ctx.load_labware(tube_rack_lname, '10')

    dest_plate = None
    if dest_temp_mod_lname:
        dest_plate = dest_temp_mod.load_labware(destination_plate_lname)
    else:
        dest_plate = ctx.load_labware(destination_plate_lname, '4')

    # load tipracks
    tipracks_left, tipracks_right = [None] * 2
    if left_pipette_tipracks_lname:
        tipracks_left = [
            ctx.load_labware(left_pipette_tipracks_lname, slot)
            for slot in ['5', '8', '11']
        ]
    if right_pipette_tipracks_lname:
        tipracks_right = [
            ctx.load_labware(right_pipette_tipracks_lname, slot)
            for slot in ['6', '9']
        ]

    # load instrument
    '''
    Nomenclature for pipette:

    use 'p'  for single-channel, 'm' for multi-channel,
    followed by number of microliters.

    p20, p300, p1000 (single channel pipettes)
    m20, m300 (multi-channel pipettes)

    If loading pipette, load with:

    ctx.load_instrument(
                        '{pipette api load name}',
                        pipette_mount ("left", or "right"),
                        tip_racks=tiprack
                        )
    '''
    left_pip = None
    right_pip = None
    pipette = None  # Remains None if there are two pipettes loaded
    if left_pipette_lname:
        left_pip = ctx.load_instrument(left_pipette_lname,
                                       "left",
                                       tip_racks=tipracks_left)
    if right_pipette_lname:
        right_pip = ctx.load_instrument(right_pipette_lname,
                                        "right",
                                        tip_racks=tipracks_right)
    if not (right_pip and left_pip):
        if right_pip:
            pipette = right_pip
        else:
            pipette = left_pip

    # Rank the pipettes by minimum volume
    s_pip, l_pip = [None] * 2
    if pipette:
        s_pip, l_pip = [pipette, pipette]
    else:
        if left_pip.min_volume < right_pip.min_volume:
            s_pip, l_pip = [left_pip, right_pip]
        else:
            s_pip, l_pip = [right_pip, left_pip]

    # pipette functions   # INCLUDE ANY BINDING TO CLASS
    '''

    Define all pipette functions, and class extensions here.
    These may include but are not limited to:

    - Custom pickup functions
    - Custom drop tip functions
    - Custom Tip tracking functions
    - Custom Trash tracking functions
    - Slow tip withdrawal

    For any functions in your protocol, describe the function as well as
    describe the parameters which are to be passed in as a docstring below
    the function (see below).

    def pick_up(pipette):
        """`pick_up()` will pause the protocol when all tip boxes are out of
        tips, prompting the user to replace all tip racks. Once tipracks are
        reset, the protocol 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 protocol (e.g. p300, m20).
        """
        try:
            pipette.pick_up_tip()
        except protocol_api.labware.OutOfTipsError:
            ctx.pause("Replace empty tip racks")
            pipette.reset_tipracks()
            pipette.pick_up_tip()

    '''
    def pick_up(pipette):
        """`pick_up()` will pause the protocol when all tip boxes are out of
        tips, prompting the user to replace all tip racks. Once tipracks are
        reset, the protocol 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 protocol (e.g. p300, m20).
        """
        try:
            pipette.pick_up_tip()
        except protocol_api.labware.OutOfTipsError:
            ctx.pause("Replace empty tip racks")
            pipette.reset_tipracks()
            pipette.pick_up_tip()

    # helper functions
    '''
    Define any custom helper functions outside of the pipette scope here, using
    the convention seen above.

    e.g.

    def remove_supernatant(vol, index):
        """
        function description

        :param vol:

        :param index:
        """


    '''

    def choose_pipette(vol, multi_action=True):
        """
        Choose pipette selects an appropriate pipette based on
        the volume involved, and whether the pipette action involves all
        8 columns or a single well.

        :param vol: The volume to use this pipette with
        :param multi_action: True if the pipette action will be done with
        an 8-channel pipette, i.e. involving an 8-channel source and/or target

        """
        nonlocal s_pip, l_pip, pipette
        # Case when only one pipette has been loaded
        if pipette:
            if pipette.min_volume < vol:
                raise Exception(
                    ("\n\nThe loaded pipette has a minimum "
                     "volume of {} which is greater than {}. " +
                     "Consider adding a smaller volume pipette\n").format(
                         pipette.min_volume, vol))
            if pipette.channels == 8:
                return pipette, True
            else:
                return pipette, False

        s_pip_is_multi = True if s_pip.channels == 8 else False
        l_pip_is_multi = True if l_pip.channels == 8 else False

        if s_pip.min_volume > vol:
            raise Exception(("The volume ({} uL)is too small to handle for " +
                             "either pipette, please re-examine your" +
                             "parameters").format(vol))

        # The preference is for the multi-channel pipette with the largest
        # volume capability while the least preferred is the smallest volume
        # single channel pipette.
        if multi_action:
            # Prefer the multi-channel pipettes if available
            if l_pip_is_multi and l_pip.min_volume < vol:
                return l_pip, True
            elif s_pip_is_multi:
                return s_pip, True
            # If they are not, let a single channel pipette do the job of a
            # multi-channel pipette
            elif not l_pip_is_multi and l_pip.min_volume < vol:
                return l_pip, False
            else:
                return s_pip, False
        else:
            if not l_pip_is_multi and l_pip.min_volume < vol:
                return l_pip, False
            elif not s_pip_is_multi:
                return s_pip, False
            else:
                raise Exception(("No approriate single channel pipette is " +
                                 "loaded for the volume of {} uL".format(vol)))

    def transfer(pip, volume, source, dest, **kwargs):
        """
        A wrapper function for InstrumentContext.transfer that handles
        labware.OutOfTipsError by asking the user to refill empty tipracks.

        :param pip: The pipette to user for the transfer

        Other parameters: See class
        opentrons.protocol_api.contexts.InstrumentContext
        """
        try:
            pip.transfer(volume, source, dest, **kwargs)
        except protocol_api.labware.OutOfTipsError:
            ctx.pause("\n\nReplace empty tip racks for {}\n".format(pip.name))
            pip.reset_tipracks()
            pip.transfer(volume, source, dest, **kwargs)

    def reag_to_wells_or_col_transfer(vol,
                                      reag_source_well,
                                      dest_plate,
                                      multi_transfer=True,
                                      **transfer_kwargs):
        """
        function description

        :param vol:

        :param index:
        """
        nonlocal n_columns, n_samples
        pip, pip_is_multi = choose_pipette(vol, multi_transfer)

        if pip_is_multi:
            dest_columns = dest_plate.columns()[0:n_columns]
            for col in dest_columns:
                transfer(pip, vol, reag_source_well, col[0], **transfer_kwargs)
        else:  # Transfer to each well
            transfer(pip, vol, reag_source_well,
                     dest_plate.wells()[0:n_samples], **transfer_kwargs)

    def remove_supernatant(vol,
                           source_plate,
                           multi_transfer=True,
                           **transfer_kwargs):
        """
        Removes a volume from each sample well of the source plate
        (well 0 to well n_samples) and transfers it to the liquid trash
        well of the reservoir.

        :param vol (float): The volume to transfer to the trash.

        :param source_plate (labware plate): The plate to aspirate from.

        :param multi_transfer (Boolean): Use 8-channel pipette and transfer
        a whole column at a time if true, otherwise use a single channel
        pipette and transfer well by well.

        :param **transfer_kwargs: Any keyword arguments that you may want
        to pass into the transfer method calls
        """
        nonlocal n_columns, n_samples
        pip, pip_is_multi = choose_pipette(vol, multi_transfer)

        if pip_is_multi:
            source_columns = source_plate.columns()[0:n_columns]
            for col in source_columns:
                transfer(pip, vol, col[0], waste_well, **transfer_kwargs)
        else:  # Transfer from each well
            transfer(pip, vol,
                     source_plate.wells()[0:n_samples], waste_well,
                     **transfer_kwargs)

    def transfer_plate_to_plate(vol, source_plate, destination_plate):
        pip, is_multi = choose_pipette(vol, True)
        if is_multi:
            for s_col, d_col in zip(source_plate.columns(),
                                    destination_plate.columns()):
                transfer(pip, vol, s_col[0], d_col[0])
        else:
            transfer(pip, vol, sample_wells, dest_wells)

    # reagents
    '''
    Define where all reagents are on the deck using the labware defined above.

    e.g.

    water = reservoir12.wells()[-1]
    waste = reservoir.wells()[0]
    samples = plate.rows()[0][0]
    dnase = tuberack.wells_by_name()['A4']

    '''

    lysis_buffer_well = reservoir.wells_by_name()['A1']
    wash_buffer_well = reservoir.wells_by_name()['A2']
    elution_buffer_well = reservoir.wells_by_name()['A3']
    nacl_well = reservoir.wells_by_name()['A4']
    bead_well = reservoir.wells_by_name()['A5']
    waste_well = reservoir.wells()[-1].top(-2)
    dnaseI_tube = None
    if dnaseI_tuberack:
        dnaseI_tube = dnaseI_tuberack.wells_by_name()['A1']
    sds_page_buf_well = None
    if do_SDS_step:
        sds_page_buf_well = reservoir.wells_by_name()['A6']

    # plate, tube rack maps
    '''
    Define any plate or tube maps here.

    e.g.

    plate_wells_by_row = [well for row in plate.rows() for well in row]

    '''
    sample_wells = sample_plate.wells()[0:n_samples]

    dest_columns = dest_plate.columns()[0:n_columns]
    dest_wells = dest_plate.wells()[0:n_samples]

    # protocol
    '''

    Include header sections as follows for each "section" of your protocol.

    Section can be defined as a step in a bench protocol.

    e.g.

    ctx.comment('\n\nMOVING MASTERMIX TO SAMPLES IN COLUMNS 1-6\n')

    for .... in ...:
        ...
        ...

    ctx.comment('\n\nRUNNING THERMOCYCLER PROFILE\n')

    ...
    ...
    ...


    '''
    ctx.comment('\n\nAdding lysis buffer to samples\n')
    pip, pip_is_multi = choose_pipette(lysis_buffer_vol)

    reag_to_wells_or_col_transfer(lysis_buffer_vol, lysis_buffer_well,
                                  sample_plate, True)

    if do_DNAse_step:
        ctx.comment('\n\nAdding DNAse I to sample wells\n')
        # Must be single channel, protocol will raise exception otherwise
        reag_to_wells_or_col_transfer(dnaseI_vol, dnaseI_tube, sample_plate,
                                      False)

    ctx.pause("\n\nPlace sample plate on a shaker and shake for 10-20" +
              " minutes at room temperature for the lysis reaction" +
              " to complete\n")

    # Optional addition of NaCl for improved binding to beads
    if use_NaCl:
        ctx.comment("Adding NaCl to samples for a final conc. of 500 mM")
        reag_to_wells_or_col_transfer(nacl_first_step_vol, nacl_well,
                                      sample_plate, True)

    if do_vortex_pause:
        ctx.pause("Pause to vortex/resuspend your magnetic beads")

    # Mixing the beads in the bead well
    pick_up(l_pip)
    l_pip.mix(n_bead_mixes, l_pip.max_volume, bead_well)

    ctx.comment("\n\nTransferring bead solution to sample wells and mixing")
    pip, pip_is_multi = choose_pipette(bead_volume, True)
    if pip_is_multi:
        for col in dest_columns:
            if not pip.has_tip:
                pick_up(pip)
            pip.aspirate(bead_volume, bead_well)
            pip.dispense(bead_volume, col[0])
            mix_vol = (pip.max_volume if total_vol_after_bead_adddn /
                       2 > pip.max_volume else total_vol_after_bead_adddn / 2)
            pip.mix(5, mix_vol, col[0])
            pip.drop_tip()
    else:
        for well in sample_wells:
            if not pip.has_tip:
                pick_up(pip)
            pip.aspirate(bead_volume, bead_well)
            pip.dispense(bead_volume, well)
            mix_vol = (pip.max_volume if total_vol_after_bead_adddn /
                       2 > pip.max_volume else total_vol_after_bead_adddn / 2)
            pip.mix(5, mix_vol, well)
            pip.drop_tip()

    ctx.comment("\n\nIncubating beads\n")
    ctx.delay(0, incubation_time)
    ctx.comment("\n\nEngaging magnets\n")
    mag_mod.engage()
    ctx.delay(0, mag_engage_time)
    ctx.comment("\n\nRemoving supernatant\n")
    remove_supernatant(total_vol_after_bead_adddn, sample_plate)

    # Wash the beads n_washes times, the standard is 3 washes
    repetitions = 1 if do_SDS_step else n_washes
    for i in range(0, repetitions):
        ctx.comment("\n\nBead wash #{}".format(i + 1))
        mag_mod.disengage()
        # Transfer wash buffer to the sample wells
        supernatant_volume = (wash_buf_vol +
                              nacl_wash_buf_vol if use_NaCl else wash_buf_vol)
        half_supernatant_vol = supernatant_volume / 2
        mix_vol = (half_supernatant_vol
                   if half_supernatant_vol < l_pip.max_volume else
                   l_pip.max_volume)
        if use_NaCl:
            reag_to_wells_or_col_transfer(wash_buf_vol, wash_buffer_well,
                                          sample_plate, True)
            reag_to_wells_or_col_transfer(nacl_wash_buf_vol,
                                          nacl_well,
                                          sample_plate,
                                          True,
                                          mix_after=(n_wash_mixes, mix_vol))
        else:
            reag_to_wells_or_col_transfer(wash_buf_vol,
                                          wash_buffer_well,
                                          sample_plate,
                                          True,
                                          mix_after=(n_wash_mixes, mix_vol))
        mag_mod.engage()
        ctx.delay(0, mag_engage_time)
        # Remove supernatant
        remove_supernatant(supernatant_volume, sample_plate)

    mag_mod.disengage()

    if do_SDS_step:
        ctx.comment("\n\nAdding 1x SDS-PAGE buffer\n")
        reag_to_wells_or_col_transfer(sds_buffer_vol, sds_page_buf_well,
                                      sample_plate, True)
        mag_mod.engage()
        ctx.delay(0, mag_engage_time)
        # Transfer to target plate
        ctx.comment("\n\nTransferring protein in SDS-buffer to target plate\n")
        transfer_plate_to_plate(sds_buffer_vol, sample_plate, dest_plate)
    # Elute
    else:
        ctx.comment("\n\nAdding elution buffer and mixing\n")
        reag_to_wells_or_col_transfer(elution_buf_vol,
                                      elution_buffer_well,
                                      sample_plate,
                                      True,
                                      mix_after=(n_elution_mixes, mix_vol))
        ctx.comment("\n\nIncubating samples with elution buffer\n")
        ctx.delay(0, incubation_time)
        ctx.comment("\n\nAttracting beads to magnets\n")
        mag_mod.engage()
        ctx.delay(0, mag_engage_time)
        ctx.comment("\n\nTransferring protein elution supernatant to" +
                    "target plate\n")
        transfer_plate_to_plate(elution_buf_vol, sample_plate, dest_plate)
    ctx.comment("\n\n~~~~~ End of protocol ~~~~~\n")
Example #20
0
def run(protocol: protocol_api.ProtocolContext):
    if debug: print(protocol)

    tiprack_300 = protocol.load_labware('opentrons_96_tiprack_300ul',
                                        labwarePositions.tiprack_300,
                                        "tiprack 300ul")

    if debug: print(tiprack_300)

    pipette_300 = protocol.load_instrument('p300_single',
                                           'right',
                                           tip_racks=[tiprack_300])
    pipette_300.flow_rate.dispense = default_flow_rate
    pipette_300.flow_rate.aspirate = default_flow_rate
    pipette_300.starting_tip = tiprack_300.well(
        tiprack_starting_pos['tiprack_300'])

    if debug: print(pipette_300)

    black_96 = protocol.load_labware(type_of_96well_plate,
                                     labwarePositions.antibodies_plate,
                                     type_of_96well_plate)

    trough12 = protocol.load_labware('parhelia_12trough',
                                     labwarePositions.buffers_reservoir,
                                     '12-trough buffers reservoir')
    if (not retreaval):
        par2 = protocol.load_labware('par2s_9slides_blue_v2',
                                     labwarePositions.par2,
                                     'par2s_9slides_blue_v2')
    if retreaval:
        temp_mod = protocol.load_module('temperature module',
                                        labwarePositions.heatmodule)

        par2 = temp_mod.load_labware('par2s_9slides_blue_v2')

    if debug: print(par2)

    buffer_wells = trough12.wells_by_name()

    buffers = Object()
    buffers.retreaval = buffer_wells['A1']
    buffers.TBS_wash = buffer_wells['A2']
    buffers.water = buffer_wells['A3']
    buffers.storage = buffer_wells['A4']
    buffers.eth_70perc_ = buffer_wells['A5']
    buffers.eth_80perc = buffer_wells['A6']
    buffers.eth_95perc = buffer_wells['A7']
    buffers.eth_100perc = buffer_wells['A8']
    buffers.hematoxylin = buffer_wells['A12']

    preblock_wells = black_96.rows()[0]
    antibody_wells = black_96.rows()[1]
    enzymeblock_wells = black_96.rows()[2]
    hrpsecondaryab_wells = black_96.rows()[3]
    substrate_wells = black_96.rows()[4]
    DAB_wells = black_96.rows()[5]

    sample_chambers = []

    for well in wellslist:
        sample_chambers.append(par2.wells_by_name()[well])

    if debug: print(sample_chambers)

    #################PROTOCOL####################
    protocol.home()
    if retreaval:
        washSamples(pipette_300, buffers.retreaval, buffers.retreaval, 0, 1,
                    extra_bottom_gap)
        washSamples(pipette_300, buffers.retreaval, sample_chambers,
                    wash_volume, 2, extra_bottom_gap)
        temp_mod.set_temperature(95)
        print("retreaval")
        protocol.delay(minutes=15)
        washSamples(pipette_300, buffers.retreaval, sample_chambers,
                    wash_volume, 1, extra_bottom_gap)
        protocol.delay(minutes=15)
        washSamples(pipette_300, buffers.retreaval, sample_chambers,
                    wash_volume, 1, extra_bottom_gap)
        protocol.delay(minutes=15)
        print("cooling down to RT")
        temp_mod.set_temperature(25)
        protocol.delay(minutes=20)

    # WASHING SAMPLES WITH TBS
    print("washing in TBS")
    washSamples(pipette_300, buffers.TBS_wash, buffers.TBS_wash, 0, 1,
                extra_bottom_gap)
    washSamples(pipette_300, buffers.TBS_wash, sample_chambers, wash_volume, 2,
                extra_bottom_gap)

    # Preblocking
    print("preblocking")
    print(len(wellslist))
    for i in range(len(wellslist)):
        print(i)
        washSamples(pipette_300, preblock_wells[i], sample_chambers[i],
                    wash_volume, 1, extra_bottom_gap)
    print("preblocking incubation: 15 min")
    protocol.delay(minutes=15)

    # APPLYING ANTIBODY COCKTAILS TO SAMPLES
    print("applying antibodies")
    for i in range(len(wellslist)):
        print(i)
        washSamples(pipette_300, antibody_wells[i], sample_chambers[i],
                    wash_volume, 1, extra_bottom_gap)

    # INCUBATE FOR DESIRED TIME
    print("staining incubation: " + str(primary_ab_incubation_time_minutes) +
          "min")
    protocol.delay(minutes=primary_ab_incubation_time_minutes)

    # WASHING SAMPLES WITH TBS
    # three individual repeats below is because they need particular incubation time between them
    print("washing with TBS")
    for i in range(5):
        washSamples(pipette_300, buffers.TBS_wash, sample_chambers,
                    wash_volume, 1, extra_bottom_gap)
        protocol.delay(minutes=3)

    # APPLYING enzyme blocking
    print("applying enzyme blocking")
    for i in range(len(wellslist)):
        washSamples(pipette_300, enzymeblock_wells[i], sample_chambers[i],
                    wash_volume, 1, extra_bottom_gap)
    # INCUBATE 10 MIN
    print("hrp blocking incubation: 10min")
    protocol.delay(minutes=10)
    washSamples(pipette_300, buffers.TBS_wash, sample_chambers, wash_volume, 3,
                extra_bottom_gap)

    # APPLYING HRP SECONDARY ANTIBODY COCKTAILS TO SAMPLES
    print("applying hrpsecondaryab")
    for i in range(len(wellslist)):
        washSamples(pipette_300, hrpsecondaryab_wells[i], sample_chambers[i],
                    wash_volume, 1, extra_bottom_gap)

    # INCUBATE FOR DESIRED TIME
    print("staining incubation: " + str(secondary_ab_incubation_time_minutes) +
          "min")
    protocol.delay(minutes=secondary_ab_incubation_time_minutes)

    # three individual repeats below is because they need particular incubation time between them
    print("washing with TBS")
    for i in range(3):
        washSamples(pipette_300, buffers.TBS_wash, sample_chambers,
                    wash_volume, 1, extra_bottom_gap)
        protocol.delay(minutes=3)

    # DILUTING AND APPLYING THE DAB
    for i in range(len(wellslist)):
        dilute_and_apply_fixative(pipette_300, DAB_wells[i],
                                  substrate_wells[i], sample_chambers[i], 200)

    print("developing substrate")

    protocol.delay(minutes=10)

    washSamples(pipette_300, buffers.water, buffers.water, 0, 1,
                extra_bottom_gap)
    washSamples(pipette_300, buffers.water, sample_chambers, wash_volume, 5,
                extra_bottom_gap)

    # STORAGE, washing samples every hour
    washSamples(pipette_300, buffers.storage, buffers.storage, 0, 1,
                extra_bottom_gap)
    for i in range(48):
        washSamples(pipette_300,
                    buffers.storage,
                    sample_chambers,
                    wash_volume / 2,
                    1,
                    extra_bottom_gap,
                    keep_tip=True)
        protocol.delay(minutes=60)
        print("total dispensed volume: ", str(stats.volume))
def transfer(
    volume_ul: int = 0,
    dispense_all: bool = True,
    pipette: InstrumentContext = None,
    source: Labware = [],
    dest: Labware = [],
    mix_before: Tuple[int] = None,
    mix_after: Tuple[int] = None,
    touch_tip: Tuple[int] = None,
    delay_time_s: int = None,
    protocol: protocol_api.ProtocolContext = None,
):
    """
    Custom transfer function; when the volume needed exceeds the pipette's max
    volume this function will prioritize tip reuse by pipetting to the top of
    the wells until the last dispensation

    Args:
        volume_ul: The requested pipetting volume.
        dispense_all: To dispense the entire volume of the pipette.
        pipette: Which pipette to perform the operation with.
        source: The labware that is being aspirated from.
        dest: The labware being dispensed to.
        mix_before: Whether to perform mixing before the transfer process.
        mix_after: Whether to perform mixing after the transfer process.
        touch_tip: Whether to allow the tip to be submerged.
        delay_time_s: How long to delay while aspirating.
        protocol: The protocol context to operate on.
    """
    # must pick up tip first before proper working volume is calculated
    pipette.pick_up_tip()
    max_vol = pipette.hw_pipette["working_volume"]
    if mix_before and len(mix_before) == 2:
        mix_before_vol = max_vol if mix_before[1] > max_vol else mix_before[1]
    if mix_after and len(mix_after) == 2:
        mix_after_vol = max_vol if mix_after[1] > max_vol else mix_after[1]

    n = math.ceil(volume_ul / max_vol)
    vol_ar = [
        volume_ul // n + (1 if x < volume_ul % n else 0) for x in range(n)
    ]

    # dispense to the top of the well so we can reuse the tips
    for v in vol_ar[:-1]:
        if mix_before:
            if len(mix_before) == 1:
                pipette.mix(
                    repetitions=mix_before[0],
                    volume=v,
                    location=source[0],
                )
            if len(mix_before) == 2:
                pipette.mix(
                    repetitions=mix_before[0],
                    volume=mix_before_vol,
                    location=source[0],
                )
        pipette.aspirate(volume=v, location=source[0])
        if delay_time_s:
            pipette.air_gap(volume=0)
            protocol.delay(seconds=delay_time_s)

        dispense_vol = v if dispense_all else v - 10
        pipette.dispense(volume=dispense_vol, location=dest[0].top())
        pipette.blow_out(location=dest[0])

    # the final transfer
    if mix_before:
        if len(mix_before) == 1:
            pipette.mix(
                repetitions=mix_before[0],
                volume=vol_ar[-1],
                location=source[0],
            )
        if len(mix_before) == 2:
            pipette.mix(
                repetitions=mix_before[0],
                volume=mix_after_vol,
                location=source[0],
            )
    pipette.aspirate(volume=vol_ar[-1], location=source[0])
    if delay_time_s:
        pipette.air_gap(volume=0)
        protocol.delay(seconds=delay_time_s)

    dispense_vol = vol_ar[-1] if dispense_all else vol_ar[-1] - 10
    pipette.dispense(volume=dispense_vol, location=dest[0])

    if mix_after:
        if len(mix_after) == 1:
            pipette.mix(repetitions=mix_after[0], volume=vol_ar[-1])
        if len(mix_after) == 2:
            pipette.mix(repetitions=mix_after[0], volume=mix_after_vol)

    pipette.blow_out(location=dest[0])
    if touch_tip:
        pipette.touch_tip(
            radius=touch_tip[0],
            v_offset=touch_tip[1],
            speed=TOUCH_SPEED,
        )
    pipette.drop_tip()
Example #22
0
def run(protocol: protocol_api.ProtocolContext):

    # set tweakable variables
    columns_to_extract = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
                          12]  # which columns should be cleaned up?
    bead_volume = 14  # 0.7x volume already in wells for size selection, 1.8x for other uses
    aspirate_speed = 7  # speed (ul/s) with which to draw liquids off beads (5-10 optimal?)
    reservoir_speed = 80  # speed (ul/s)  with which to draw liquids from reservoir
    wash_volume = 150  # ul of ethanol for bead washes
    elution_volume = 30  # ul of water to add to final beads
    elution_to_plate = 20  # ul to transfer to final elution plate
    incubation_time = 5  #number of minutes for DNA to mix with beads before capture
    capture_time = 2  #number of minutes to capture on stand
    dry_time = 5  #number of minutes to dry beads
    reservoir = True  #If the using the 12 channel reservoirs, go True, otherwise dispense into 96-well deep well plate along similar columns.
    vertical_space = 2  #number of mm for pipette head to be above well for dispensing
    well_space = 1  #number of mm from bottom of well to draw from (default is 1mm)
    mix_beads = False  #should the beads be mixed before use?

    # define deck layout
    MagModule = protocol.load_module('magnetic module gen2', 1)
    BindingPlate = MagModule.load_labware('biorad_96_wellplate_200ul_pcr')
    if reservoir:
        BeadsAndWater = protocol.load_labware(
            'usascientific_12_reservoir_22ml', '2'
        )  # magbeads in A1 (Nsamples * bead_volume * 1.2), 80% Ethanol in A2 (Nsamples * wash_volume * 1.2), 80% Ethanol in A3 (Nsamples * wash_volume * 1.2), water in A4 (Nsamples * elution_volume * 1.2))
    else:
        BeadsAndWater = protocol.load_labware(
            'usascientific_96_wellplate_2.4ml_deep', '2'
        )  #This is an alternate using USA scientific deep well 2mL plates
    ElutionPlate = protocol.load_labware('biorad_96_wellplate_200ul_pcr',
                                         '3')  # an empty biorad 96 well plate
    tips_bind = protocol.load_labware('opentrons_96_filtertiprack_200ul', '4')
    tips_wash1 = protocol.load_labware('opentrons_96_filtertiprack_200ul', '5')
    tips_wash2 = protocol.load_labware('opentrons_96_filtertiprack_200ul', '6')
    tips_elute = protocol.load_labware('opentrons_96_filtertiprack_200ul', '7')
    Waste = protocol.load_labware('agilent_1_reservoir_290ml', '11')

    # define pipettes
    right_pipette = protocol.load_instrument(
        'p300_multi_gen2',
        'right',
        tip_racks=[tips_bind, tips_wash1, tips_wash2, tips_elute])

    ### Prerun setup ########################################
    MagModule.disengage()

    ### Binding ########################################
    #mix up beads
    if mix_beads:
        protocol.comment('-----------------------> Mixing beads')
        right_pipette.pick_up_tip(tips_bind['A1'])
        right_pipette.mix(
            10, 150, BeadsAndWater['A1']
        )  # mix beads 10by pulling up 100ul x by pulling up 100ul
        right_pipette.blow_out()
        right_pipette.touch_tip()
        right_pipette.return_tip()

    # add defined volume of beads to each well
    protocol.comment('-----------------------> Adding beads')
    for i in columns_to_extract:
        right_pipette.pick_up_tip(tips_bind['A' + str(i)])
        right_pipette.aspirate(bead_volume, BeadsAndWater['A1'])
        right_pipette.touch_tip()
        right_pipette.dispense(bead_volume, BindingPlate['A' + str(i)])
        right_pipette.mix(10, 35, BindingPlate['A' + str(i)])
        right_pipette.blow_out()
        right_pipette.touch_tip()
        right_pipette.return_tip()
    protocol.delay(minutes=incubation_time)
    # capture beads
    protocol.comment('-----------------------> Capturing beads')
    MagModule.engage()
    protocol.delay(minutes=capture_time)
    # Remove buffer
    protocol.comment('-----------------------> Removing buffer')
    right_pipette.flow_rate.aspirate = aspirate_speed
    for i in columns_to_extract:
        right_pipette.pick_up_tip(tips_bind['A' + str(i)])
        right_pipette.aspirate(bead_volume * 2.2, BindingPlate['A' + str(i)])
        right_pipette.dispense(200, Waste['A1'])
        right_pipette.drop_tip()

    ### Wash 1 ########################################
    protocol.comment('-----------------------> Adding EtOH: Wash 1')
    right_pipette.flow_rate.aspirate = reservoir_speed
    right_pipette.pick_up_tip(tips_wash1['A1'])
    for i in columns_to_extract:
        right_pipette.aspirate(wash_volume, BeadsAndWater['A2'])
        right_pipette.dispense(wash_volume,
                               BindingPlate['A' + str(i)].top(vertical_space))
    right_pipette.return_tip()
    right_pipette.flow_rate.aspirate = aspirate_speed
    for i in columns_to_extract:
        right_pipette.pick_up_tip(tips_wash1['A' + str(i)])
        right_pipette.aspirate(wash_volume * 1.2,
                               BindingPlate['A' + str(i)].bottom(well_space))
        right_pipette.dispense(200, Waste['A1'])
        right_pipette.drop_tip()

    ### Wash 2 ########################################
    protocol.comment('-----------------------> Adding EtOH: Wash 2')
    right_pipette.flow_rate.aspirate = reservoir_speed
    right_pipette.pick_up_tip(tips_wash2['A1'])
    for i in columns_to_extract:
        right_pipette.aspirate(wash_volume, BeadsAndWater['A3'])
        right_pipette.dispense(wash_volume,
                               BindingPlate['A' + str(i)].top(vertical_space))
    right_pipette.return_tip()
    right_pipette.flow_rate.aspirate = aspirate_speed
    for i in columns_to_extract:
        right_pipette.pick_up_tip(tips_wash2['A' + str(i)])
        right_pipette.aspirate(wash_volume * 1.2,
                               BindingPlate['A' + str(i)].bottom(well_space))
        right_pipette.dispense(200, Waste['A1'])
        right_pipette.drop_tip()

    ### Drying ########################################
    protocol.comment('-----------------------> Drying beads')
    protocol.delay(minutes=dry_time)

    ### Elution ########################################
    MagModule.disengage()

    right_pipette.flow_rate.aspirate = reservoir_speed
    for i in columns_to_extract:
        right_pipette.pick_up_tip(tips_elute['A' + str(i)])
        right_pipette.aspirate(elution_volume, BeadsAndWater['A4'])
        right_pipette.dispense(elution_volume, BindingPlate['A' + str(i)])
        right_pipette.mix(5, elution_volume * 0.7, BindingPlate['A' + str(i)])
        right_pipette.blow_out()
        right_pipette.touch_tip()
        right_pipette.return_tip()

    MagModule.engage()
    protocol.delay(minutes=capture_time)
    right_pipette.flow_rate.aspirate = aspirate_speed
    for i in columns_to_extract:
        right_pipette.pick_up_tip(tips_elute['A' + str(i)])
        right_pipette.aspirate(elution_to_plate, BindingPlate['A' + str(i)])
        right_pipette.dispense(elution_to_plate, ElutionPlate['A' + str(i)])
        right_pipette.drop_tip()
Example #23
0
def run(protocol: protocol_api.ProtocolContext):

	# which steps should be run?
	AddBeads = True
	AddBindingBuffer = True
	CaptureBinding = True
	Wash1 = True
	Wash2 = True
	Wash2repeat = True
	Dry = True
	Elute = True

	# set tweakable variables
	elution_volume = 100 # ul of water to add to final beads
	elution_to_plate = 70 # ul to transfer to final elution plate
	capture_depth = -3 # depth below ideal bottom of plate to remove supernatants, this may be required as a function of a poor calibration or labware def
	capture_min = 2 # number of minutes to capture beads on magnets
	cols_to_extract = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] # which columns should be extracted?
	nmix = 5 # number of times to pipette to mix
	drying_min = 20 # number of minutes to evaporate residual ethanol !!!! SET TO 20
	trash_speed = 1 # the relative speed to discard of liquids into trash, this is an integer multiplier of normal speed, set higher to clear bubbles on outside of tip


	
	# define deck layout
	MagModule = protocol.load_module('magnetic module gen2', 10)
	BindingPlate = MagModule.load_labware('nest_96_wellplate_2ml_deep') # use the
	ElutionPlate = protocol.load_labware('biorad_96_wellplate_200ul_pcr', '3') # an empty biorad 96 well plate

	BeadsAndWater = protocol.load_labware('usascientific_12_reservoir_22ml', '2') # magbeads in A1 (4 mL), water in A2 (10mL), the end columns will be used for waste
	BindingBuffer = protocol.load_labware('agilent_1_reservoir_290ml', '7') # reservoir with 70 mL binding buffer
	MagWash1 = protocol.load_labware('agilent_1_reservoir_290ml', '4') # reservoir with 100 mL magwash1
	MagWash2 = protocol.load_labware('agilent_1_reservoir_290ml', '1') # reservoir with 200 mL magwash2

	tips_binding = protocol.load_labware('opentrons_96_filtertiprack_200ul', '11')
	tips_wash1 =  protocol.load_labware('opentrons_96_filtertiprack_200ul', '8')
	tips_wash2 =  protocol.load_labware('opentrons_96_filtertiprack_200ul', '5')
	tips_wash2_repeat =  protocol.load_labware('opentrons_96_filtertiprack_200ul', '9')
	tips_elution = protocol.load_labware('opentrons_96_filtertiprack_200ul', '6')

	fixed_trash = protocol.fixed_trash['A1']


	set_rail_lights = True

	# define pipettes
	multichannel = protocol.load_instrument('p300_multi_gen2', 'left', tip_racks=[tips_binding, tips_wash1, tips_wash2, tips_wash2_repeat, tips_elution])
	#P1000 = protocol.load_instrument('p1000_single_gen2', 'right', tip_racks=[tips_binding, tips_wash1, tips_wash2, tips_wash2rep])

	### Prerun setup ########################################
	MagModule.disengage()

	### MAG BINDING ######################################

	if AddBindingBuffer:
		protocol.comment('--------->Adding 600 ul binding buffer')
		multichannel.pick_up_tip(tips_binding['A1'])
		for i in cols_to_extract:
			multichannel.aspirate(200, BindingBuffer['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingBuffer['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingBuffer['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
		multichannel.return_tip()
		
	if AddBeads:
		protocol.comment('--------->Adding 25ul mag beads')
		multichannel.pick_up_tip(tips_binding['A2'])
		multichannel.mix(10, 100, BeadsAndWater['A1'].bottom(3)) # mix beads 20 x by pulling up 100ul
		for i in cols_to_extract:
			multichannel.aspirate(25, BeadsAndWater['A1'])
			multichannel.dispense(25, BindingPlate['A'+str(i)].top(4)
		multichannel.return_tip()
		for i in cols_to_extract:
			multichannel.pick_up_tip(tips_binding['A'+str(i)])
			multichannel.mix(10, 200, BeadsAndWater['A1'].bottom(3))
			multichannel.return_tip()
		
	if CaptureBinding:
		protocol.comment('--------->Removing Binding Buffer')
		MagModule.engage()
		protocol.delay(minutes=capture_min)
		for i in cols_to_extract:
			multichannel.pick_up_tip(tips_binding['A'+str(i)])
			multichannel.aspirate(200, BindingPlate['A'+str(i)])
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.touch_tip()
			multichannel.aspirate(200, BindingPlate['A'+str(i)])
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.touch_tip()
			multichannel.aspirate(200, BindingPlate['A'+str(i)])
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingPlate['A'+str(i)].bottom(capture_depth), rate=0.2)
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.return_tip()
		
	if Wash1:
		protocol.comment('--------->Doing Wash 1')
		MagModule.disengage()
		multichannel.pick_up_tip(tips_wash1['A1'])
		for i in cols_to_extract:
			multichannel.aspirate(200, MagWash1['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
			multichannel.aspirate(200, MagWash1['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
			multichannel.aspirate(200, MagWash1['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
			multichannel.aspirate(200, MagWash1['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
		multichannel.return_tip()	
		for i in cols_to_extract:
			multichannel.pick_up_tip(tips_wash1['A'+str(i)])
			multichannel.aspirate(100, MagWash1['A1'])
			multichannel.dispense(100, BindingPlate['A'+str(i)])
			multichannel.mix(nmix, 180, BindingPlate['A'+str(i)].bottom(2))
			multichannel.blow_out()
			multichannel.return_tip()
		MagModule.engage()
		protocol.delay(minutes=capture_min)
		for i in cols_to_extract:
			multichannel.pick_up_tip(tips_wash1['A'+str(i)])
			multichannel.aspirate(200, BindingPlate['A'+str(i)])
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingPlate['A'+str(i)])
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingPlate['A'+str(i)])
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingPlate['A'+str(i)])
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingPlate['A'+str(i)].bottom(capture_depth), rate=0.2)
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			multichannel.blow_out()
			multichannel.return_tip()
			
	if Wash2:
		protocol.comment('--------->Doing Wash 2')
		MagModule.disengage()
		multichannel.pick_up_tip(tips_wash2['A1'])
		for i in cols_to_extract:
			multichannel.aspirate(200, MagWash2['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
			multichannel.aspirate(200, MagWash2['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
			multichannel.aspirate(200, MagWash2['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
			multichannel.aspirate(200, MagWash2['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
		multichannel.return_tip()	
		for i in cols_to_extract:
			multichannel.pick_up_tip(tips_wash2['A'+str(i)])
			multichannel.aspirate(100, MagWash2['A1'])
			multichannel.dispense(100, BindingPlate['A'+str(i)])
			multichannel.mix(nmix, 180, BindingPlate['A'+str(i)].bottom(2))
			multichannel.blow_out()
			multichannel.return_tip()
		MagModule.engage()
		protocol.delay(minutes=capture_min)
		for i in cols_to_extract:
			multichannel.pick_up_tip(tips_wash2['A'+str(i)])
			multichannel.aspirate(200, BindingPlate['A'+str(i)])
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingPlate['A'+str(i)])
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingPlate['A'+str(i)])
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingPlate['A'+str(i)]) # is this a calibration issue?
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingPlate['A'+str(i)].bottom(capture_depth), rate=0.2)
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.return_tip()
			
	if Wash2repeat:
		protocol.comment('--------->Repeating Wash 2')
		MagModule.disengage()
		multichannel.pick_up_tip(tips_wash2_repeat['A1'])
		for i in cols_to_extract:
			multichannel.aspirate(200, MagWash2['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
			multichannel.aspirate(200, MagWash2['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
			multichannel.aspirate(200, MagWash2['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
			multichannel.aspirate(200, MagWash2['A1'])
			multichannel.dispense(200, BindingPlate['A'+str(i)].top(4))
			#multichannel.blow_out()
		multichannel.return_tip()	
		for i in cols_to_extract:
			multichannel.pick_up_tip(tips_wash2_repeat['A'+str(i)])
			multichannel.aspirate(100, MagWash2['A1'])
			multichannel.dispense(100, BindingPlate['A'+str(i)])
			multichannel.mix(nmix, 180, BindingPlate['A'+str(i)].bottom(5))
			multichannel.blow_out()
			multichannel.return_tip()
		MagModule.engage()
		protocol.delay(minutes=capture_min)
		for i in cols_to_extract:
			multichannel.pick_up_tip(tips_wash2_repeat['A'+str(i)])
			multichannel.aspirate(200, BindingPlate['A'+str(i)])
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingPlate['A'+str(i)])
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingPlate['A'+str(i)])
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingPlate['A'+str(i)]) # is this a calibration issue?
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.aspirate(200, BindingPlate['A'+str(i)].bottom(capture_depth), rate=0.2)
			multichannel.dispense(200, fixed_trash, rate = trash_speed)
			#multichannel.blow_out()
			multichannel.return_tip()
	
	if Dry:
		protocol.comment('--------->Drying DNA')
		protocol.delay(minutes=drying_min)

	if Elute:
		protocol.comment('--------->Eluting DNA')
		MagModule.disengage()
		for i in cols_to_extract:
			multichannel.pick_up_tip(tips_elution['A'+str(i)])
			multichannel.aspirate(elution_volume, BeadsAndWater['A2'])
			multichannel.dispense(elution_volume, BindingPlate['A'+str(i)])
			multichannel.mix(nmix, elution_to_plate, BindingPlate['A'+str(i)].bottom(capture_depth))
			#multichannel.blow_out()
			multichannel.return_tip()
		MagModule.engage()
		protocol.delay(minutes=capture_min)
		for i in cols_to_extract:
			multichannel.pick_up_tip(tips_elution['A'+str(i)])
			multichannel.aspirate(elution_to_plate, BindingPlate['A'+str(i)].bottom(capture_depth+1), rate=0.2)
			multichannel.dispense(elution_to_plate, ElutionPlate['A'+str(i)])
			#multichannel.blow_out()
			multichannel.return_tip()

			
	
			
Example #24
0
def run(ctx: protocol_api.ProtocolContext):

    [
     _num_col,
     _filter_tips,
     _mbl5_vol,
     _mag_height,
     _m300_mount
    ] = get_values(  # noqa: F821 (<--- DO NOT REMOVE!)
        "_num_col",
        "_filter_tips",
        "_mbl5_vol",
        "_mag_height",
        "_m300_mount")

    # VARIABLES
    num_col = _num_col
    filter_tips = _filter_tips
    m300_mount = _m300_mount
    mag_height = _mag_height
    mbl5_vol = int(_mbl5_vol)

    # load module
    mag_mod = ctx.load_module('magnetic module gen2', '1')

    # load labware
    mag_plate = mag_mod.load_labware('96_squarewell_block_macherey_nagel')
    res1 = ctx.load_labware('nest_12_reservoir_15ml', '3')
    res2 = ctx.load_labware('nest_12_reservoir_15ml', '6')
    waste_res = res2 = ctx.load_labware('nest_12_reservoir_15ml', '9')
    elute_plate = ctx.load_labware('abgene_96_wellplate_700ul', '2')

    # load tip_racks
    tipracks = [ctx.load_labware('opentrons_96_filtertiprack_200ul'
                                 if filter_tips
                                 else 'opentrons_96_tiprack_300ul',
                                 slot) for slot in ['4', '5', '7',
                                                    '8', '10', '11']]

    # load instrument
    m300 = ctx.load_instrument('p300_multi_gen2',
                               m300_mount, tip_racks=tipracks)

    def pick_up():
        try:
            m300.pick_up_tip()
        except protocol_api.labware.OutOfTipsError:
            ctx.pause("Replace all tip racks on Slots 7, 8, 10, and 11")
            m300.reset_tipracks()
            m300.pick_up_tip()

    waste_vol_ctr = 0
    waste_well_ctr = 0

    def remove_supernatant():
        nonlocal waste_vol_ctr
        nonlocal waste_well_ctr

        ctx.comment('\n\n\nREMOVING SUPERNATANT\n')
        for i, col in enumerate(sample_cols):
            side = -1 if i % 2 == 0 else 1
            aspirate_loc = col.bottom(1).move(
                    Point(x=(col.length/2-2)*side))
            pick_up()
            for _ in range(2):
                m300.aspirate(200 if filter_tips else 300, aspirate_loc, rate=0.6)  # noqa E501
                m300.dispense(200 if filter_tips else 300, waste_res.wells()[waste_well_ctr])    # noqa E501
                m300.blow_out(waste_res.wells()[waste_well_ctr].top())
                waste_vol_ctr += 200
                if waste_vol_ctr >= 12000:
                    waste_vol_ctr = 0
                    waste_well_ctr += 1
            m300.drop_tip()

    # map liquids
    num_samp = num_col*8
    bead_buffer_wells = math.ceil(num_samp*162.5/10000)
    mbl3_wells = math.ceil(num_samp*800/10000)
    eth_wells = math.ceil(num_samp*400/10000)

    prok = res1.wells()[0]
    bead_buffer = res1.wells()[1:1+bead_buffer_wells]*num_col
    mbl3 = res1.wells()[4:4+mbl3_wells]*num_col
    ethanol = res2.wells()[:eth_wells]*num_col
    mbl5 = res2.wells()[-1]
    sample_cols = mag_plate.rows()[0][:num_col]

    ctx.comment('\n\n\nDISPENSING PRO-K\n')
    for col in sample_cols:
        pick_up()
        m300.aspirate(50, prok)
        m300.dispense(50, col)
        m300.mix(5, 90, col)
        m300.drop_tip()

    ctx.comment('\n\n\nDISPENSING BEAD BUFFER\n')
    airgap = 20
    for reagent_col, col in zip(bead_buffer, sample_cols):
        pick_up()
        m300.mix(5, 200 if filter_tips else 300, reagent_col, rate=2.0)
        m300.aspirate(162.5, reagent_col)
        m300.air_gap(airgap)
        m300.dispense(162.5+airgap, col)
        m300.mix(5, 150, col)
        m300.air_gap(airgap)
        m300.drop_tip()

    mag_mod.engage(height_from_base=mag_height)
    ctx.delay(minutes=3)
    remove_supernatant()
    mag_mod.disengage()

    ctx.comment('\n\n\nDISPENSING MBL3\n')
    for reagent_col, col in zip(mbl3, sample_cols):
        pick_up()
        m300.aspirate(200, reagent_col)
        m300.dispense(200, col.top())
        m300.aspirate(200, reagent_col)
        m300.dispense(200, col)
        m300.mix(5, 200 if filter_tips else 300, col)
        m300.drop_tip()

    mag_mod.engage(height_from_base=mag_height)
    ctx.delay(minutes=3)
    remove_supernatant()
    mag_mod.disengage()

    ctx.comment('\n\n\nDISPENSING ETHANOL\n')
    for reagent_col, col in zip(ethanol, sample_cols):
        pick_up()
        m300.aspirate(200, reagent_col)
        m300.dispense(200, col.top())
        m300.aspirate(200, reagent_col)
        m300.dispense(200, col)
        m300.mix(5, 200 if filter_tips else 300, col)
        m300.drop_tip()

    mag_mod.engage(height_from_base=mag_height)
    ctx.delay(minutes=3)
    remove_supernatant()
    ctx.delay(minutes=20)
    mag_mod.disengage()

    ctx.comment('\n\n\nDISPENSING MBL5\n')
    for col in sample_cols:
        pick_up()
        m300.aspirate(mbl5_vol, mbl5)
        m300.dispense(mbl5_vol, col)
        m300.mix(5, 0.6*mbl5_vol, col)
        m300.drop_tip()

    mag_mod.engage(height_from_base=mag_height)

    for i, (sample_col, elute_col) in enumerate(
                                    zip(sample_cols, elute_plate.rows()[0])):
        side = -1 if i % 2 == 0 else 1
        aspirate_loc = sample_col.bottom(1).move(
                Point(x=(sample_col.length/2-2)*side))
        pick_up()
        m300.aspirate(mbl5_vol, aspirate_loc, rate=0.6)
        m300.dispense(mbl5_vol, elute_col)
        m300.drop_tip()
Example #25
0
def run(protocol: protocol_api.ProtocolContext):
    if debug: print(protocol)

    tiprack_300 = protocol.load_labware('opentrons_96_tiprack_300ul',
                                        labwarePositions.tiprack_300,
                                        "tiprack 300ul")

    if debug: print(tiprack_300)
    pipette_300 = protocol.load_instrument(
        'p300_single_gen2' if pipette_300_GEN == 'GEN2' else 'p300_single',
        pipette_300_location,
        tip_racks=[tiprack_300])
    #    pipette_300 = protocol.load_instrument('p300_single', 'right', tip_racks=[tiprack_300])
    pipette_300.flow_rate.dispense = default_flow_rate
    pipette_300.flow_rate.aspirate = default_flow_rate
    pipette_300.starting_tip = tiprack_300.wells()[tiprack_300_starting_pos -
                                                   1]
    # pipette_300.starting_tip = tiprack_300.well(tiprack_starting_pos['tiprack_300'])

    if debug: print(pipette_300)

    black_96 = protocol.load_labware(type_of_96well_plate,
                                     labwarePositions.antibodies_plate,
                                     type_of_96well_plate)

    trough12 = protocol.load_labware('parhelia_12trough',
                                     labwarePositions.buffers_reservoir,
                                     '12-trough buffers reservoir')
    if (not retrieval):
        par2 = protocol.load_labware(omniStainer_type, labwarePositions.par2,
                                     omniStainer_type)
    if retrieval:
        temp_mod = protocol.load_module('temperature module',
                                        labwarePositions.heatmodule)

        par2 = temp_mod.load_labware(omniStainer_type)
    wellslist = list(par2.wells_by_name().keys())
    wellslist = wellslist[1:num_samples + 1]
    if debug: print(par2)

    buffer_wells = trough12.wells_by_name()

    buffers = Object()
    buffers.retrieval = buffer_wells['A1']
    buffers.TBS_wash = buffer_wells['A2']
    buffers.water = buffer_wells['A3']
    buffers.storage = buffer_wells['A4']
    buffers.eth_70perc_ = buffer_wells['A5']
    buffers.eth_80perc = buffer_wells['A6']
    buffers.eth_95perc = buffer_wells['A7']
    buffers.eth_100perc = buffer_wells['A8']
    buffers.hematoxylin = buffer_wells['A12']

    preblock_wells = black_96.rows()[0]
    antibody_wells = black_96.rows()[5]
    enzymeblock_wells = black_96.rows()[1]
    hrpsecondaryab_wells = black_96.rows()[2]
    substrate_wells = black_96.rows()[3]
    DAB_wells = black_96.rows()[4]

    sample_chambers = []

    for well in wellslist:
        sample_chambers.append(par2.wells_by_name()[well])

    if debug: print(sample_chambers)

    #################PROTOCOL####################
    protocol.home()

    if lid == 'yes':
        openPar2(protocol, pipette_300, par2)

    if retrieval:
        washSamples(pipette_300, buffers.retrieval, buffers.retrieval, 2, 1,
                    extra_bottom_gap + 18)
        washSamples(pipette_300, buffers.retrieval, sample_chambers,
                    wash_volume, 2, extra_bottom_gap)

        if lid == 'yes':
            closePar2(protocol, pipette_300, par2)

        temp_mod.set_temperature(95)
        print("retrieval")
        protocol.delay(minutes=15)
        #        washSamples(pipette_300, buffers.retrieval, sample_chambers, wash_volume, 1, extra_bottom_gap)
        protocol.delay(minutes=15)
        #        washSamples(pipette_300, buffers.retrieval, sample_chambers, wash_volume, 1, extra_bottom_gap)
        protocol.delay(minutes=15)
        print("cooling down to RT")
        temp_mod.set_temperature(25)
        protocol.delay(minutes=20)
        if lid == 'yes':
            openPar2(protocol, pipette_300, par2)

    # WASHING SAMPLES WITH TBS
    print("washing in TBS")
    washSamples(pipette_300, buffers.TBS_wash, buffers.TBS_wash, 2, 1,
                extra_bottom_gap + 18)
    washSamples(pipette_300, buffers.TBS_wash, sample_chambers, wash_volume, 2,
                extra_bottom_gap)

    # Preblocking
    print("preblocking")
    print(len(wellslist))

    print("puncturing preblock wells")
    for i in range(len(wellslist)):
        print(i)
        washSamples(pipette_300,
                    preblock_wells[i],
                    preblock_wells[i],
                    2,
                    1,
                    extra_bottom_gap + 18,
                    keep_tip=True)
    pipette_300.drop_tip()

    print("applying the preblock")
    for i in range(len(wellslist)):
        print(i)
        washSamples(pipette_300, preblock_wells[i], sample_chambers[i],
                    ab_volume, 1, extra_bottom_gap)
    print("preblocking incubation: 15 min")
    protocol.delay(minutes=15)

    # APPLYING ANTIBODY COCKTAILS TO SAMPLES

    print("puncturing and applying abs")
    for i in range(len(wellslist)):
        print(i)
        washSamples(pipette_300,
                    antibody_wells[i],
                    antibody_wells[i],
                    2,
                    1,
                    extra_bottom_gap + 18,
                    keep_tip=True)
        washSamples(pipette_300, antibody_wells[i], sample_chambers[i],
                    ab_volume, 1, extra_bottom_gap)

    if lid == 'yes':
        closePar2(protocol, pipette_300, par2)

    # INCUBATE FOR DESIRED TIME
    print("staining incubation: " + str(primary_ab_incubation_time_minutes) +
          "min")
    protocol.delay(minutes=primary_ab_incubation_time_minutes)

    if lid == 'yes':
        openPar2(protocol, pipette_300, par2)

    # WASHING SAMPLES WITH TBS
    # three individual repeats below is because they need particular incubation time between them
    print("washing with TBS")
    for i in range(5):
        washSamples(pipette_300, buffers.TBS_wash, sample_chambers,
                    wash_volume, 1, extra_bottom_gap)
        protocol.delay(minutes=3)

    # APPLYING enzyme blocking
    print("puncturing enzyme blocking wells")
    for i in range(len(wellslist)):
        washSamples(pipette_300,
                    enzymeblock_wells[i],
                    enzymeblock_wells[i],
                    2,
                    1,
                    extra_bottom_gap + 18,
                    keep_tip=True)
    pipette_300.drop_tip()

    print("applying enzyme blocking")
    for i in range(len(wellslist)):
        washSamples(pipette_300, enzymeblock_wells[i], sample_chambers[i],
                    ab_volume, 1, extra_bottom_gap)
    # INCUBATE 10 MIN
    print("hrp blocking incubation: 10min")
    protocol.delay(minutes=10)

    washSamples(pipette_300, buffers.TBS_wash, sample_chambers, wash_volume, 3,
                extra_bottom_gap)

    # APPLYING HRP SECONDARY ANTIBODY COCKTAILS TO SAMPLES
    print("puncturing hrpsecondaryab wells")
    for i in range(len(wellslist)):
        washSamples(pipette_300,
                    hrpsecondaryab_wells[i],
                    hrpsecondaryab_wells[i],
                    2,
                    1,
                    extra_bottom_gap + 18,
                    keep_tip=True)
    pipette_300.drop_tip()

    print("applying hrpsecondaryab")
    for i in range(len(wellslist)):
        washSamples(pipette_300, hrpsecondaryab_wells[i], sample_chambers[i],
                    ab_volume, 1, extra_bottom_gap)
    if lid == 'yes':
        closePar2(protocol, pipette_300, par2)

    # INCUBATE FOR DESIRED TIME
    print("staining incubation: " + str(secondary_ab_incubation_time_minutes) +
          "min")
    protocol.delay(minutes=secondary_ab_incubation_time_minutes)

    if lid == 'yes':
        openPar2(protocol, pipette_300, par2)

    # three individual repeats below is because they need particular incubation time between them
    print("washing with TBS")
    for i in range(3):
        washSamples(pipette_300, buffers.TBS_wash, sample_chambers,
                    wash_volume, 1, extra_bottom_gap)
        protocol.delay(minutes=3)

    # DILUTING AND APPLYING THE DAB
    print("puncturing the DAB wells")
    for i in range(len(wellslist)):
        washSamples(pipette_300, DAB_wells[i], DAB_wells[i], 2, 1,
                    extra_bottom_gap + 18)
    print("puncturing the substrate wells")
    for i in range(len(wellslist)):
        washSamples(pipette_300,
                    substrate_wells[i],
                    substrate_wells[i],
                    2,
                    1,
                    extra_bottom_gap + 18,
                    keep_tip=True)
    pipette_300.drop_tip()

    print("applying DAB")
    for i in range(len(wellslist)):
        dilute_and_apply_fixative(pipette_300, DAB_wells[i],
                                  substrate_wells[i], sample_chambers[i],
                                  wash_volume)

    print("developing substrate")

    protocol.delay(minutes=10)

    washSamples(pipette_300, buffers.water, buffers.water, 2, 1,
                extra_bottom_gap + 18)
    washSamples(pipette_300, buffers.water, sample_chambers, wash_volume, 5,
                extra_bottom_gap)
    if lid == 'yes':
        closePar2(protocol, pipette_300, par2)
Example #26
0
def run(protocol: protocol_api.ProtocolContext):

    # LABWARE
    fuge_rack = protocol.load_labware('vwr_24_tuberack_1500ul', '1')
    std_rack = protocol.load_labware('vwr_24_tuberack_1500ul', '2')
    tiprack300 = protocol.load_labware('opentrons_96_filtertiprack_200ul', '8')
    tiprack20 = protocol.load_labware('opentrons_96_filtertiprack_20ul', '9')
    tempdeck = protocol.load_module(
        'tempdeck', '10')  # have this so I don't have to move it off
    holder_1 = protocol.load_labware(
        '8wstriptubesonfilterracks_96_aluminumblock_250ul', '3')
    holder_2 = protocol.load_labware(
        '8wstriptubesonfilterracks_96_aluminumblock_250ul', '6')
    stds_plate = tempdeck.load_labware('abi_96_wellplate_250ul')

    # PIPETTES
    p300 = protocol.load_instrument('p300_single_gen2',
                                    'left',
                                    tip_racks=[tiprack300])
    p20 = protocol.load_instrument('p20_single_gen2',
                                   'right',
                                   tip_racks=[tiprack20])

    # REAGENTS
    std_1 = std_rack['A1']  # 900ul Water
    std_2 = std_rack['A2']  # 900ul water
    std_3 = std_rack['A3']  # 900ul water
    std_4 = std_rack['A4']  # 900ul water
    std_5 = std_rack['A5']  # 900ul water
    std_6 = std_rack['A6']  # 900ul water
    std_7 = std_rack['B1']  # 900ul water
    std_8 = std_rack['B2']  # 900ul water
    std_9 = std_rack['B3']  # 900ul water
    std_10 = std_rack['B4']  # 900ul water
    std_11 = std_rack['B5']  # 900ul water
    std_12 = std_rack['B6']  # 900ul water
    std_13 = std_rack['C1']  # 900ul water
    std_14 = std_rack['C2']  # 900ul water
    std_15 = std_rack['C3']  # 900ul water

    pos_control = fuge_rack['A1']  # 100-1000ul pos control @1uM
    mmp_tube = fuge_rack['A2']  #500 uL of master mixs and 400uL of primers
    waste = fuge_rack['D6']  # waste
    water = fuge_rack['A3']  # 100 uL water

    # LISTS
    std_wells = [std_1, std_2, std_3, std_4, std_5, std_6, std_7, std_8, std_9]
    std_conc = [std_5, std_6, std_7, std_8, std_9]
    cols = [1, 3, 5, 7, 9, 11]
    rows = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']

    ### COMMANDS ######
    # Make std dilution series
    # Make 10nM pos control, std_1
    p300.transfer(
        100,
        pos_control.bottom(2),  #1uM
        std_1.bottom(20),
        mix_after=(3, 200),  # remove residual fluid from tip
        touch_tip=False)

    # serial dilutions in microfuge tubes, 10% diliutions
    for i in range(len(std_wells) - 1):
        h_mix = 20
        p300.pick_up_tip()
        p300.mix(2, 200, std_wells[i].bottom(8))  # mix low
        p300.mix(2, 200, std_wells[i].bottom(14))  # mix mid
        p300.mix(5, 200, std_wells[i].bottom(h_mix))  #mix hi
        p300.aspirate(100, std_wells[i].bottom(h_mix), rate=0.4)
        p300.touch_tip()
        p300.dispense(
            100,
            std_wells[i + 1].bottom(14))  # better mixing with mid dispense
        p300.blow_out(
            std_wells[i + 1].bottom(h_mix))  # blow out just below the surface
        p300.drop_tip()
        if i == len(std_wells) - 2:  # last tube
            p300.pick_up_tip()
            p300.mix(2, 200, std_wells[i + 1].bottom(8))  # mix low
            p300.mix(2, 200, std_wells[i + 1].bottom(14))  # mix mid
            p300.mix(5, 200, std_wells[i + 1].bottom(h_mix))  #mix hi
            p300.blow_out(
                std_wells[i +
                          1].bottom(h_mix))  # blow out just below the surface
    p300.drop_tip()

    #add master mix and primers to PRC tubes
    for col in cols:
        p20.pick_up_tip()
        for row in rows:
            p20.aspirate(18, mmp_tube)
            p20.move_to(mmp_tube.top())
            protocol.delay(seconds=2)
            p20.touch_tip(v_offset=-5)
            p20.dispense(18, holder_1[row + str(col)])
        p20.drop_tip()

    #add first 4 standards to upper half of tubes
    count = 0  # keep track of standard
    for row in rows:
        p20.pick_up_tip()
        p20.aspirate(14, std_conc[count])  #take from standand
        p20.touch_tip()
        for col in cols:
            p20.dispense(2, holder_1[row + str(col)])  # dispense in PCR tubes
            p20.touch_tip()
        p20.dispense(2, waste)
        p20.blow_out(waste.bottom())
        p20.drop_tip()
        count = count + 1
        if count == 4:
            break

    #add first 4 standards to lower half of tubes
    count = 0  #reset count
    for row in rows[4:]:
        p20.pick_up_tip()
        p20.aspirate(8, std_conc[count])
        p20.touch_tip()
        for col in cols[0:3]:
            p20.dispense(2, holder_1[row + str(col)])
            p20.touch_tip()
        p20.dispense(2, waste)
        p20.blow_out(waste.bottom())
        p20.drop_tip()
        count = count + 1
        if count == 4:
            break

    #add final standard
    for row in rows[4:7]:
        p20.pick_up_tip()
        p20.aspirate(20, std_conc[count])
        p20.touch_tip()
        for col in cols[3:]:
            p20.dispense(2, holder_1[row + str(col)])
            p20.touch_tip()
        p20.dispense(2, waste)
        p20.blow_out(waste.bottom())
        p20.drop_tip()

    # add water to last 3 wells
    for row in rows[7:8]:
        p20.pick_up_tip()
        p20.aspirate(8, water)
        p20.touch_tip()
        for col in cols[3:]:
            p20.dispense(2, holder_1[row + str(col)])
            p20.touch_tip()
        p20.dispense(2, waste)
        p20.blow_out(waste.bottom())
        p20.drop_tip()
Example #27
0
def run(ctx: protocol_api.ProtocolContext):
    global MM_TYPE

    # check source (elution) labware type
    source_plate = ctx.load_labware(
        'opentrons_96_aluminumblock_nest_wellplate_100ul', '1',
        'chilled elution plate on block from Station B')
    tips20 = [
        ctx.load_labware('opentrons_96_filtertiprack_20ul', slot)
        for slot in ['3', '6', '8', '9', '10', '11']
    ]
    tips300 = [ctx.load_labware('opentrons_96_filtertiprack_200ul', '2')]
    tempdeck = ctx.load_module('Temperature Module Gen2', '4')
    pcr_plate = tempdeck.load_labware(
        'opentrons_96_aluminumblock_nest_wellplate_100ul', 'PCR plate')
    mm_strips = ctx.load_labware(
        'opentrons_96_aluminumblock_nest_wellplate_100ul', '7',
        'mastermix strips')
    tempdeck.set_temperature(4)
    tube_block = ctx.load_labware(
        'opentrons_24_aluminumblock_nest_2ml_screwcap', '5',
        '2ml screw tube aluminum block for mastermix + controls')

    # pipette
    m20 = ctx.load_instrument('p20_multi_gen2', 'right', tip_racks=tips20)
    p300 = ctx.load_instrument('p300_single_gen2', 'left', tip_racks=tips300)

    # setup up sample sources and destinations
    num_cols = math.ceil(NUM_SAMPLES/8)
    sources = source_plate.rows()[0][:num_cols]
    sample_dests = pcr_plate.rows()[0][:num_cols]

    tip_log = {'count': {}}
    folder_path = '/data/C'
    tip_file_path = folder_path + '/tip_log.json'
    if TIP_TRACK and not ctx.is_simulating():
        if os.path.isfile(tip_file_path):
            with open(tip_file_path) as json_file:
                data = json.load(json_file)
                if 'tips20' in data:
                    tip_log['count'][m20] = data['tips20']
                else:
                    tip_log['count'][m20] = 0
                if 'tips300' in data:
                    tip_log['count'][p300] = data['tips300']
                else:
                    tip_log['count'][p300] = 0
        else:
            tip_log['count'] = {m20: 0, p300: 0}
    else:
        tip_log['count'] = {m20: 0, p300: 0}

    tip_log['tips'] = {
        m20: [tip for rack in tips20 for tip in rack.rows()[0]],
        p300: [tip for rack in tips300 for tip in rack.wells()]
    }
    tip_log['max'] = {
        pip: len(tip_log['tips'][pip])
        for pip in [m20, p300]
    }

    def pick_up(pip):
        nonlocal tip_log
        if tip_log['count'][pip] == tip_log['max'][pip]:
            ctx.pause('Replace ' + str(pip.max_volume) + 'µl tipracks before \
resuming.')
            pip.reset_tipracks()
            tip_log['count'][pip] = 0
        pip.pick_up_tip(tip_log['tips'][pip][tip_log['count'][pip]])
        tip_log['count'][pip] += 1

    """ mastermix component maps """
    mm_tube = tube_block.wells()[0]
    mm_dict = {
        'volume': 15,
        'components': {
            tube: vol for tube, vol in zip(tube_block.columns()[1][:3],
                                           [6.25, 1.25, 7.5])
        }
    }

    vol_overage = 1.2 if NUM_SAMPLES > 48 else 1.1  # decrease overage for small sample number
    total_mm_vol = mm_dict['volume']*(NUM_SAMPLES+2)*vol_overage
    # translate total mastermix volume to starting height
    r = mm_tube.diameter/2
    mm_height = total_mm_vol/(math.pi*(r**2)) - 5

    def h_track(vol):
        nonlocal mm_height
        dh = 1.1*vol/(math.pi*(r**2))  # compensate for 10% theoretical volume loss
        mm_height = mm_height - dh if mm_height - dh > 2 else 2  # stop at 2mm above mm tube bottom
        return mm_tube.bottom(mm_height)

    if PREPARE_MASTERMIX:
        vol_overage = 1.2 if NUM_SAMPLES > 48 else 1.1

        for i, (tube, vol) in enumerate(mm_dict['components'].items()):
            comp_vol = vol*(NUM_SAMPLES)*vol_overage
            pick_up(p300)
            num_trans = math.ceil(comp_vol/160)
            vol_per_trans = comp_vol/num_trans
            for _ in range(num_trans):
                p300.air_gap(20)
                p300.aspirate(vol_per_trans, tube)
                ctx.delay(seconds=3)
                p300.touch_tip(tube)
                p300.air_gap(20)
                p300.dispense(20, mm_tube.top())  # void air gap
                p300.dispense(vol_per_trans, mm_tube.bottom(2))
                p300.dispense(20, mm_tube.top())  # void pre-loaded air gap
                p300.blow_out(mm_tube.top())
                p300.touch_tip(mm_tube)
            if i < len(mm_dict['components'].items()) - 1:  # only keep tip if last component and p300 in use
                p300.drop_tip()
        mm_total_vol = mm_dict['volume']*(NUM_SAMPLES)*vol_overage
        if not p300.hw_pipette['has_tip']:  # pickup tip with P300 if necessary for mixing
            pick_up(p300)
        mix_vol = mm_total_vol / 2 if mm_total_vol / 2 <= 200 else 200  # mix volume is 1/2 MM total, maxing at 200µl
        mix_loc = mm_tube.bottom(20) if NUM_SAMPLES > 48 else mm_tube.bottom(5)
        p300.mix(7, mix_vol, mix_loc)
        p300.blow_out(mm_tube.top())
        p300.touch_tip()

    # transfer mastermix to strips
    mm_strip = mm_strips.columns()[0]
    if not p300.hw_pipette['has_tip']:
        pick_up(p300)
    for i, well in enumerate(mm_strip):
        if NUM_SAMPLES % 8 == 0 or i < NUM_SAMPLES % 8:
            vol = num_cols*mm_dict['volume']*((vol_overage-1)/2+1)
        else:
            vol = (num_cols-1)*mm_dict['volume']*((vol_overage-1)/2+1)
        p300.transfer(vol, mm_tube, well, new_tip='never')
    p300.drop_tip()

    # transfer mastermix to plate
    mm_vol = mm_dict['volume']
    pick_up(m20)
    m20.transfer(mm_vol, mm_strip[0].bottom(0.5), sample_dests,
                 new_tip='never')
    m20.drop_tip()

    # transfer samples to corresponding locations
    for s, d in zip(sources, sample_dests):
        pick_up(m20)
        m20.transfer(SAMPLE_VOL, s.bottom(2), d.bottom(2), new_tip='never')
        m20.mix(1, 10, d.bottom(2))
        m20.blow_out(d.top(-2))
        m20.aspirate(5, d.top(2))  # suck in any remaining droplets on way to trash
        m20.drop_tip()

    # track final used tip
    if TIP_TRACK and not ctx.is_simulating():
        if not os.path.isdir(folder_path):
            os.mkdir(folder_path)
        data = {
            'tips20': tip_log['count'][m20],
            'tips300': tip_log['count'][p300]
        }
        with open(tip_file_path, 'w') as outfile:
            json.dump(data, outfile)
def run(ctx: protocol_api.ProtocolContext):

    # load labware and modules
    tempdeck = ctx.load_module('tempdeck', '1')
    elution_plate = tempdeck.load_labware(
        'opentrons_96_aluminumblock_nest_wellplate_100ul',
        'cooled elution plate')
    reagent_res1 = ctx.load_labware('nest_12_reservoir_15ml', '2',
                                    'reagent reservoir 1')
    magdeck = ctx.load_module('magdeck', '4')
    magplate = magdeck.load_labware('usascientific_96_wellplate_2.4ml_deep')
    reagent_res2 = ctx.load_labware('nest_12_reservoir_15ml', '5',
                                    'reagent reservoir 2')
    waste = ctx.load_labware('nest_1_reservoir_195ml', '7',
                             'waste reservoir').wells()[0].top()
    tips300 = [
        ctx.load_labware('opentrons_96_filtertiprack_200ul', slot,
                         '300µl tiprack')
        for slot in ['3', '6', '8', '9', '10', '11']
    ]

    # reagents and samples
    num_cols = math.ceil(NUM_SAMPLES / 8)
    mag_samples_m = [
        well for well in magplate.rows()[0][0::2] + magplate.rows()[0][1::2]
    ][:num_cols]
    elution_samples_m = [
        well
        for well in elution_plate.rows()[0][0::2] + magplate.rows()[0][1::2]
    ][:num_cols]

    viral_dna_rna_buff = reagent_res1.wells()[:3]
    beads = reagent_res1.wells()[3]
    wash_1 = reagent_res1.wells()[4:8]
    wash_2 = reagent_res1.wells()[8:]
    etoh = reagent_res2.wells()[:8]
    water = reagent_res2.wells()[-1]

    # pipettes
    m300 = ctx.load_instrument('p300_multi', 'left', tip_racks=tips300)
    m300.flow_rate.aspirate = 150
    m300.flow_rate.dispense = 300

    tip_counts = {m300: 0}
    tip_maxes = {m300: len(tips300) * 12}

    def pick_up(pip):
        nonlocal tip_counts
        if tip_counts[pip] == tip_maxes[pip]:
            ctx.pause('Replace ' + str(pip.max_volume) + 'µl tipracks before \
    resuming.')
            pip.reset_tipracks()
            tip_counts[pip] = 0
        tip_counts[pip] += 1
        pip.pick_up_tip()

    def remove_supernatant(vol):
        m300.flow_rate.aspirate = 30
        num_trans = math.ceil(vol / 270)
        vol_per_trans = vol / num_trans
        for i, m in enumerate(mag_samples_m):
            side = -1 if i < 6 == 0 else 1
            loc = m.bottom(0.5).move(Point(x=side * 2))
            if not m300.hw_pipette['has_tip']:
                pick_up(m300)
            for _ in range(num_trans):
                m300.move_to(m.center())
                m300.transfer(vol_per_trans,
                              loc,
                              waste,
                              new_tip='never',
                              air_gap=30)
                m300.blow_out(waste)
            m300.drop_tip()
        m300.flow_rate.aspirate = 150

    # transfer viral DNA/RNA buffer
    for i, m in enumerate(mag_samples_m):
        pick_up(m300)
        m300.transfer(400,
                      viral_dna_rna_buff[i // 4],
                      m.top(),
                      new_tip='never')
        m300.mix(10, 200, m)
        m300.blow_out(m.top(-2))
        m300.drop_tip()

    # premix, transfer, and mix magnetic beads with sample
    for i, m in enumerate(mag_samples_m):
        pick_up(m300)
        if i == 0:
            for _ in range(20):
                m300.aspirate(200, beads.bottom(3))
                m300.dispense(200, beads.bottom(20))
        m300.transfer(20, beads, m, new_tip='never')
        m300.mix(10, 200, m)
        m300.blow_out(m.top(-2))
        m300.drop_tip()

    # incubate on magnet
    magdeck.engage()
    ctx.delay(minutes=3, msg='Incubating on magnet for 3 minutes.')

    # remove supernatant
    remove_supernatant(630)

    magdeck.disengage()

    for wash in [wash_1, wash_2]:
        # transfer and mix wash
        for i, m in enumerate(mag_samples_m):
            pick_up(m300)
            side = 1 if i < 6 == 0 else -1
            loc = m.bottom(0.5).move(Point(x=side * 2))
            m300.transfer(500, wash[i // 3], m.top(), new_tip='never')
            m300.mix(10, 200, loc)
            m300.blow_out(m.top(-2))
            m300.drop_tip()

        # incubate on magnet
        magdeck.engage()
        ctx.delay(minutes=3, msg='Incubating on magnet for 3 minutes.')

        # remove supernatant
        remove_supernatant(510)

        magdeck.disengage()

    # EtOH washes
    for wash in range(2):
        # transfer and mix wash
        etoh_set = etoh[wash * 4:wash * 4 + 4]
        pick_up(m300)
        m300.transfer(500,
                      etoh_set[i // 3], [m.top(3) for m in mag_samples_m],
                      new_tip='never')
        ctx.delay(seconds=30, msg='Incubating in EtOH for 30 seconds.')

        # remove supernatant
        remove_supernatant(510)

        if wash == 1:
            ctx.delay(minutes=10, msg='Airdrying on magnet for 10 minutes.')

        magdeck.disengage()

    # transfer and mix water
    for m in mag_samples_m:
        pick_up(m300)
        side = 1 if i < 6 == 0 else -1
        loc = m.bottom(0.5).move(Point(x=side * 2))
        m300.transfer(50, water, m.top(), new_tip='never')
        m300.mix(10, 30, loc)
        m300.blow_out(m.top(-2))
        m300.drop_tip()

    # incubate on magnet
    magdeck.engage()
    ctx.delay(minutes=3, msg='Incubating on magnet for 3 minutes.')

    # transfer elution to clean plate
    m300.flow_rate.aspirate = 30
    for s, d in zip(mag_samples_m, elution_samples_m):
        pick_up(m300)
        side = -1 if i < 6 == 0 else 1
        loc = s.bottom(0.5).move(Point(x=side * 2))
        m300.transfer(50, loc, d, new_tip='never')
        m300.blow_out(d.top(-2))
        m300.drop_tip()
    m300.flow_rate.aspirate = 150
Example #29
0
def run(protocol: protocol_api.ProtocolContext):

    # LABWARE
    fuge_rack = protocol.load_labware('opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap', '11')
    tiprack20 = protocol.load_labware('opentrons_96_filtertiprack_20ul', '9')
    tempdeck = protocol.load_module('tempdeck', '10')
    # sectempdeck = protocol.load_module('tempdeck', '4')
    pcr_plate = tempdeck.load_labware('abi_96_wellplate_250ul')
    # stds_rack = sectempdeck.load_labware('opentrons_24_aluminumblock_generic_2ml_screwcap')
    ww_plate1 = protocol.load_labware('bioer_96_wellplate_2200ul', '1')
    

    # PIPETTES
    p20 = protocol.load_instrument(
        'p20_single_gen2', 'right', tip_racks=[tiprack20]
    )
    
    # REAGENTS   
    N2 = fuge_rack['A1'] # LU MasterMix
    N1 = fuge_rack['B1'] # water
    LUPositive = fuge_rack['D6'] # LU Positive Control plasmid
    mixes = [N2, N1]
     # LISTS
    rows = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
    N2_cols = [1, 2, 3, 4, 5, 6]
    N1_cols = [7, 8, 9, 10, 11, 12]

    # #### COMMANDS ######    
    # aspirate mmix to all wells in 96w plate; 15*48 = 720ul*1.1=792
    h_list = tip_heightsEpp(792, 48, 15)
    for y, pcrmix in enumerate(mixes): #12 cols
        p20.pick_up_tip()
        well_num = 1
        for z in range(1,7):
            for row in rows: #8 rows
                # print (y)
                col = 6*y+z
                dest = row+str(col)
                # print ("height is: ", h_list[well_num-1])
                p20.aspirate(15, pcrmix.bottom(h_list[well_num-1]), rate=0.75) #head vol for more accurate pipetting
                protocol.delay(seconds=1) #equilibrate
                p20.move_to(pcrmix.bottom(38))
                protocol.delay(seconds=1) #equilibrate
                p20.touch_tip(v_offset=-4)
                p20.dispense(15, pcr_plate[dest].bottom(1))
                p20.blow_out(pcr_plate[dest].bottom(8))
                p20.touch_tip()
                well_num += 1
        p20.drop_tip()

    tot_ww_plates = [ww_plate1]
    for x, ww_plate in enumerate(tot_ww_plates):
        for col in range(0,1): #samples in col 5, 11
            for row in rows:
                p20.pick_up_tip()
                source = row + str(6*col+5) #A5, B5, C5
                dest1 = row + str(6*x+6*col+1) #A1, #A2, #A3
                dest2 = row + str(6*x+6*col+2)
                dest3 = row + str(6*x+6*col+3)
                dest4 = row + str(6*x+6*col+4)
                dest5 = row + str(6*x+6*col+5)
                dest6 = row + str(6*x+6*col+6)
                dest7 = row + str(6*x+6*col+7)
                dest8 = row + str(6*x+6*col+8)
                dest9 = row + str(6*x+6*col+9)
                dest10 = row + str(6*x+6*col+10)
                dest11 = row + str(6*x+6*col+11)
                dest12 = row + str(6*x+6*col+12)
                p20.aspirate(18, ww_plate[source].bottom(1))
                protocol.delay(seconds=2) #equilibrate
                p20.dispense(5, pcr_plate[dest1].bottom(1))
                p20.touch_tip()    
                p20.dispense(5, pcr_plate[dest2].bottom(1))    
                p20.touch_tip()    
                p20.dispense(5, pcr_plate[dest3].bottom(1))    
                p20.touch_tip()    
                p20.drop_tip()
                p20.pick_up_tip()
                p20.aspirate(18, ww_plate[source].bottom(1))
                protocol.delay(seconds=2) #equilibrate
                p20.dispense(5, pcr_plate[dest4].bottom(1))
                p20.touch_tip()    
                p20.dispense(5, pcr_plate[dest5].bottom(1))
                p20.touch_tip()    
                p20.dispense(5, pcr_plate[dest6].bottom(1))
                p20.touch_tip()    
                p20.drop_tip()

                p20.pick_up_tip()                
                p20.aspirate(18, ww_plate[source].bottom(1))
                protocol.delay(seconds=2) #equilibrate
                p20.dispense(5, pcr_plate[dest7].bottom(1))
                p20.touch_tip()    
                p20.dispense(5, pcr_plate[dest8].bottom(1))    
                p20.touch_tip()    
                p20.dispense(5, pcr_plate[dest9].bottom(1))    
                p20.touch_tip()    
                p20.drop_tip()
                
                p20.pick_up_tip()
                p20.aspirate(18, ww_plate[source].bottom(1))
                protocol.delay(seconds=2) #equilibrate
                p20.dispense(5, pcr_plate[dest10].bottom(1))
                p20.touch_tip()    
                p20.dispense(5, pcr_plate[dest11].bottom(1))    
                p20.touch_tip()    
                p20.dispense(5, pcr_plate[dest12].bottom(1))    
                p20.touch_tip()    
                p20.drop_tip()
Example #30
0
def run(ctx: protocol_api.ProtocolContext):
    [
     _samp_cols,  # column numbers containing samples
     _m300_mount  # mount for p300-Multi
    ] = get_values(  # noqa: F821 (<--- DO NOT REMOVE!)
        '_samp_cols',
        '_m300_mount')

    # custom variables
    if type(_samp_cols) is int:
        samp_cols = [_samp_cols]
    else:
        samp_cols = _samp_cols.split(",")
    m300_mount = _m300_mount

    # load modules
    mag_deck = ctx.load_module('magnetic module gen2', '1')

    # load labware
    mag_plate = mag_deck.load_labware(
        'nest_96_wellplate_100ul_pcr_full_skirt',
        'Sample Plate on MagDeck')

    elution_plate = ctx.load_labware(
        'nest_96_wellplate_100ul_pcr_full_skirt', '3',
        'Elution Plate')

    res12 = ctx.load_labware(
        'nest_12_reservoir_15ml', '2', '12-Well Reservoir with Reagents')

    # load tipracks
    tips = [ctx.load_labware(
        'opentrons_96_filtertiprack_200ul', s) for s in ['5', '6']]

    # load instrument
    m300 = ctx.load_instrument('p300_multi_gen2', m300_mount, tip_racks=tips)

    # helper functions
    # to take vol and return estimated liq height
    def liq_height(well):
        if well.diameter is not None:
            radius = well.diameter / 2
            cse = math.pi*(radius**2)
        elif well.length is not None:
            cse = well.length*well.width
        else:
            cse = None
        if cse:
            return well.liq_vol / cse
        else:
            raise Exception("""Labware definition must
                supply well radius or well length and width.""")

    def incubate(min):
        ctx.comment(f'\nIncubating for {min} minutes\n')
        ctx.delay(minutes=min)

    def remove_supernatant(vol):
        ctx.comment(f'\nTransferring {vol}uL from wells to liquid waste\n')
        m300.flow_rate.aspirate = 15
        for col in samp_cols:
            m300.pick_up_tip()
            m300.aspirate(vol, mag_plate['A'+str(col).strip()])
            m300.dispense(vol, waste)
            m300.drop_tip()
        m300.flow_rate.aspirate = 94

    # reagents
    beads = res12['A1']
    beads.liq_vol = 45 * len(samp_cols) * 1.05
    etoh = res12['A3']
    etoh.liq_vol = 350 * len(samp_cols)
    te = res12['A5']
    te.liq_vol = 50 * len(samp_cols) * 1.05
    waste = res12['A11'].top(-2)

    # protocol
    # Transfer Bead Solution Transfer
    ctx.comment(f'\nTransferring 45uL Bead Solution \
    to samples in columns {samp_cols}\n')
    for col in samp_cols:
        m300.pick_up_tip()
        beads.liq_vol -= 45
        bead_ht = liq_height(beads) - 2 if liq_height(beads) - 2 > 1 else 1
        m300.mix(3, 40, beads.bottom(bead_ht))
        m300.aspirate(45, beads.bottom(bead_ht))
        m300.dispense(45, mag_plate['A'+str(col).strip()])
        m300.mix(5, 60, mag_plate['A'+str(col).strip()])
        ctx.delay(seconds=1)
        m300.drop_tip()

    # Incubate for 5 minutes, engage magnet, incubate for 2 minutes
    incubate(5)
    mag_deck.engage()
    incubate(2)

    # remove supernatant
    remove_supernatant(75)
    mag_deck.disengage()

    # Perform 2 ethanol washes
    for i in range(2):
        ctx.comment(f'\nPerforming EtOH Wash {i+1}\n')
        for col in samp_cols:
            m300.pick_up_tip()
            etoh.liq_vol -= 150
            et_ht = liq_height(etoh) - 2 if liq_height(etoh) - 2 > 1 else 1
            m300.aspirate(150, etoh.bottom(et_ht))
            m300.dispense(150, mag_plate['A'+str(col).strip()])
            m300.mix(5, 100, mag_plate['A'+str(col).strip()])
            ctx.delay(seconds=1)
            m300.blow_out()
            m300.drop_tip()

        mag_deck.engage()
        incubate(2)

        remove_supernatant(150)
        mag_deck.disengage()

    incubate(2)

    # Transfer elution buffer and elutes
    ctx.comment(f'\nTransferring 50uL Low TE \
    to samples in columns {samp_cols}\n')
    for col in samp_cols:
        m300.pick_up_tip()
        te.liq_vol -= 50
        te_ht = liq_height(te) - 2 if liq_height(te) - 2 > 1 else 1
        m300.aspirate(50, te.bottom(te_ht))
        m300.dispense(50, mag_plate['A'+str(col).strip()])
        m300.mix(5, 25, mag_plate['A'+str(col).strip()])
        ctx.delay(seconds=1)
        m300.drop_tip()

    incubate(2)
    mag_deck.engage()
    incubate(2)

    ctx.comment('\nTransferring samples to Elution Plate\n')
    m300.flow_rate.aspirate = 30
    for col, dest in zip(samp_cols, elution_plate.rows()[0]):
        m300.pick_up_tip()
        m300.aspirate(50, mag_plate['A'+str(col).strip()])
        m300.dispense(50, dest)
        m300.drop_tip()

    ctx.comment('\nProtocol complete!')