Example #1
0
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 = 5
    #########################################################################################################
    ##  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",
                                     3,
                                     label="Output plate")
    #Tips - Ordered in the way they are used
    tiprack2 = protocol.load_labware("opentrons_96_filtertiprack_200ul", 4)
    p300 = protocol.load_instrument("p300_multi_gen2", "left", [tiprack2])

    bottomHeight = 0.5
    bottomMixHeight = 1
    generalHeight = 5
    topOffset = -5
    moveSide = 0

    def getMixingTopHeight(stringLabware, volume):
        labwareDefinition = protocol_api.labware.get_labware_definition(
            stringLabware)
        shape = labwareDefinition["wells"]["A1"]["shape"]
        if shape == "circular":
            diameter = labwareDefinition["wells"]["A1"]["diameter"]
            height = (math.pi * diameter**2) / volume
        else:
            width = labwareDefinition["wells"]["A1"]["xDimension"]
            length = labwareDefinition["wells"]["A1"]["yDimension"]
            height = volume / (width * length)

    def well_mix(vol,
                 loc,
                 reps,
                 labwareName="eppendorf_96_deepwell_2ml",
                 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 = 100
        p300.flow_rate.dispense = 300
        height = getMixingTopHeight(labwareName, vol)
        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, loc1)
        p300.flow_rate.aspirate = 50
        p300.flow_rate.dispense = 150
        p300.dispense(20, loc.top(topOffset))

    p300.pick_up_tip(tiprack2["D1"])
    well_mix(100,
             deepPlate["A1"],
             10,
             labwareName="eppendorf_96_deepwell_2ml",
             moveSide=1,
             bottomHeight=0.8)

    magneto.disengage()
    #p300.pick_up_tip(tiprack2["D1"].top().move(types.Point(x=0, y=-36, z=0)))
    protocol.delay(seconds=20)
    p300.move_to(reagents["A1"].bottom().move(
        types.Point(x=0, y=0, z=bottomHeight)))
    protocol.delay(seconds=10)
    p300.move_to(deepPlate["A1"].bottom().move(
        types.Point(x=1, y=0, z=bottomMixHeight)))
    protocol.delay(seconds=5)

    p300.move_to(outplate["A1"].bottom().move(types.Point(x=0, y=0, z=5)))
    protocol.delay(seconds=10)
    p300.move_to(deepPlate["A1"].bottom().move(
        types.Point(x=-1, y=0, z=bottomHeight)))
    protocol.delay(seconds=5)
    well_mix(100, deepPlate["A1"], 10, moveSide=-1)
    p300.return_tip()
    magneto.disengage()
    protocol.delay(minutes=10)

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

    slots_map = {
        '1': 'starlabpcrplateonws_96_wellplate_350ul',
        '2': 'opentrons_24_tuberack_generic_2ml_screwcap',
        '3': 'opentrons_24_tuberack_generic_2ml_screwcap',
        '5': 'opentrons_24_tuberack_generic_2ml_screwcap',
        '6': 'opentrons_24_tuberack_generic_2ml_screwcap',
    }

    # Configure tip racks and pipette

    r_pipette_name = 'p300_single'
    r_tiprack_slots = ['4']
    # r_tiprack_name = 'opentrons_96_tiprack_300ul'
    r_tiprack_name = 'tipone_96_diytiprack_300ul'

    # l_pipette_name = 'p10_multi'
    # l_tiprack_slots = ['2']
    # l_tiprack_name = 'geb_96_tiprack_10ul'

    labware_items = {}
    for slot, labware_item in slots_map.items():
        labware_items.update({slot: protocol.load_labware(labware_item, slot)})

    r_tip_racks = [
        protocol.load_labware(r_tiprack_name, slot) for slot in r_tiprack_slots
    ]
    # l_tip_racks = [protocol.load_labware(l_tiprack_name, slot) for slot in l_tiprack_slots]

    r_pipette = protocol.load_instrument(instrument_name=r_pipette_name,
                                         mount='right',
                                         tip_racks=r_tip_racks)
    # l_pipette = protocol.load_instrument(instrument_name = l_pipette_name,
    # mount = 'left', tip_racks = l_tip_racks)

    inst_list = [
        # '170$1_A1->2_A1',
        # '170$1_A2->2_A2',
        # '170$1_A3->2_A3',
        # '170$1_A4->2_A4',
        # '170$1_A5->2_A5',
        # '170$1_A6->2_A6',
        # '170$1_A7->2_B1',
        # '170$1_A8->2_B2',
        # '170$1_A9->2_B3',
        # '170$1_A10->2_B4',
        # '170$1_A11->2_B5',
        # '170$1_A12->2_B6',
        # '170$1_B1->2_C1',
        # '170$1_B2->2_C2',
        # '170$1_B3->2_C3',
        # '170$1_B4->2_C4',
        # '170$1_B5->2_C5',
        # '170$1_B6->2_C6',
        # '170$1_B7->2_D1',
        # '170$1_B8->2_D2',
        # '170$1_B9->2_D3',
        # '170$1_B10->2_D4',
        # '170$1_B11->2_D5',
        # '170$1_B12->2_D6',
        # '170$1_C1->3_A1',
        # '170$1_C2->3_A2',
        # '170$1_C3->3_A3',
        # '170$1_C4->3_A4',
        # '170$1_C5->3_A5',
        # '170$1_C6->3_A6',
        # '170$1_C7->3_B1',
        # '170$1_C8->3_B2',
        # '170$1_C9->3_B3',
        # '170$1_C10->3_B4',
        # '170$1_C11->3_B5',
        # '170$1_C12->3_B6',
        # '170$1_D1->3_C1',
        # '170$1_D2->3_C2',
        # '170$1_D3->3_C3',
        # '170$1_D4->3_C4',
        # '170$1_D5->3_C5',
        # '170$1_D6->3_C6',
        # '170$1_D7->3_D1',
        # '170$1_D8->3_D2',
        # '170$1_D9->3_D3',
        # '170$1_D10->3_D4',
        # '170$1_D11->3_D5',
        # '170$1_D12->3_D6',
        '170$1_E1->5_A1',
        '170$1_E2->5_A2',
        '170$1_E3->5_A3',
        '170$1_E4->5_A4',
        '170$1_E5->5_A5',
        '170$1_E6->5_A6',
        '170$1_E7->5_B1',
        '170$1_E8->5_B2',
        '170$1_E9->5_B3',
        '170$1_E10->5_B4',
        '170$1_E11->5_B5',
        '170$1_E12->5_B6',
        '170$1_F1->5_C1',
        '170$1_F2->5_C2',
        '170$1_F3->5_C3',
        '170$1_F4->5_C4',
        '170$1_F5->5_C5',
        '170$1_F6->5_C6',
        '170$1_F7->5_D1',
        '170$1_F8->5_D2',
        '170$1_F9->5_D3',
        '170$1_F10->5_D4',
        '170$1_F11->5_D5',
        '170$1_F12->5_D6',
        '170$1_G1->6_A1',
        '170$1_G2->6_A2',
        '170$1_G3->6_A3',
        '170$1_G4->6_A4',
        '170$1_G5->6_A5',
        '170$1_G6->6_A6',
        '170$1_G7->6_B1',
        '170$1_G8->6_B2',
        '170$1_G9->6_B3',
        '170$1_G10->6_B4',
        '170$1_G11->6_B5',
        '170$1_G12->6_B6',
        '170$1_H1->6_C1',
        '170$1_H2->6_C2',
        '170$1_H3->6_C3',
        '170$1_H4->6_C4',
        '170$1_H5->6_C5',
        '170$1_H6->6_C6',
        '170$1_H7->6_D1',
        '170$1_H8->6_D2',
        '170$1_H9->6_D3'
    ]

    for inst in inst_list:

        vol, path = inst.split('$')
        vol = int(vol)
        source, dest = path.split('->')
        source_slot, source_well = source.split('_')
        dest_slot, dest_well = dest.split('_')

        r_pipette.pick_up_tip(r_tip_racks[0].wells_by_name()[source_well])
        r_pipette.aspirate(
            vol, labware_items[source_slot].wells_by_name()[source_well])
        r_pipette.dispense(
            vol, labware_items[dest_slot].wells_by_name()[dest_well].top(-2))
        r_pipette.aspirate(100)
        r_pipette.dispense(100)
        r_pipette.aspirate(100)
        r_pipette.dispense(100)
        r_pipette.blow_out()
        r_pipette.drop_tip()
def run(ctx: protocol_api.ProtocolContext):

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

    # define tips
    tips20 = [
        ctx.load_labware('opentrons_96_filtertiprack_20ul', slot)
        for slot in ['6', '9', '8', '7']
    ]
    tips300 = [ctx.load_labware('opentrons_96_filtertiprack_200ul', '3')]

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

    # tempdeck module
    tempdeck = ctx.load_module('tempdeck', '10')
    tempdeck.set_temperature(4)

    # check mastermix labware type
    if MM_LABWARE not in MM_LW_DICT:
        raise Exception('Invalid MM_LABWARE. Must be one of the following:\n' +
                        '\n'.join(list(MM_LW_DICT.keys())))

    # load mastermix labware
    mm_rack = ctx.load_labware(MM_LW_DICT[MM_LABWARE], '11', MM_LABWARE)

    # check mastermix tube labware type
    if MMTUBE_LABWARE not in MMTUBE_LW_DICT:
        raise Exception(
            'Invalid MMTUBE_LABWARE. Must be one of the following:\n' +
            '\n'.join(list(MMTUBE_LW_DICT.keys())))

    # This one is not loaded, it contains the raius of each tube to calculate volume height

    # check pcr plate
    if PCR_LABWARE not in PCR_LW_DICT:
        raise Exception(
            'Invalid PCR_LABWARE. Must be one of the following:\n' +
            '\n'.join(list(PCR_LW_DICT.keys())))

    # load pcr plate
    pcr_plate = tempdeck.load_labware(PCR_LW_DICT[PCR_LABWARE], 'PCR plate')

    # check source (elution) labware type
    if ELUTION_LABWARE not in EL_LW_DICT:
        raise Exception(
            'Invalid ELUTION_LABWARE. Must be one of the following:\n' +
            '\n'.join(list(EL_LW_DICT.keys())))

    # load elution labware
    if 'plate' in ELUTION_LABWARE:
        source_racks = ctx.load_labware(EL_LW_DICT[ELUTION_LABWARE], '1',
                                        'RNA elution labware')
    else:
        source_racks = [
            ctx.load_labware(EL_LW_DICT[ELUTION_LABWARE], slot,
                             'RNA elution labware ' + str(i + 1))
            for i, slot in enumerate(['4', '1', '5', '2'])
        ]

    # setup sample sources and destinations
    sources, dests = get_source_dest_coordinates(ELUTION_LABWARE, source_racks,
                                                 pcr_plate)

    # prepare mastermix
    if PREPARE_MASTERMIX:
        mm_tube = prepare_mastermix(MM_TYPE, mm_rack, p300, p20)
    else:
        mm_tube = mm_rack.wells()[0]
        if TRANSFER_MASTERMIX:
            homogenize_mm(mm_tube, p300)

    # transfer mastermix
    if TRANSFER_MASTERMIX:
        transfer_mastermix(mm_tube, dests, VOLUME_MMIX, p300, p20)

    # transfer samples to corresponding locations
    if TRANSFER_SAMPLES:
        transfer_samples(ELUTION_LABWARE, sources, dests, p20)

    finish_run()
Example #4
0
def run(protocol: protocol_api.ProtocolContext):
    """
    Pipette 30uL of water from a 5mL tube to 12 PCR strips.
    Using a new tip for every step so that we can check if there is no big
    difference between volumes from different pipette tip locations.
    """
    # =============================================================================

    # ======================LOADING LABWARE AND PIPETTES===========================
    # =============================================================================
    ## For available labware see "labware/list_of_available_labware".       ##
    # Pipette tips
    ##### !!! OPTION 1: ROBOT
    tip_one_300 = protocol.load_labware(
        'tipone_96_tiprack_300ul',  #labware definition
        1,  #deck position
        '300tips')  #custom name
    ##### !!! OPTION 2: SIMULATOR
    # with open("labware/tipone_96_tiprack_300ul/"
    #             "tipone_96_tiprack_300ul.json") as labware_file:
    #           labware_def_tips = json.load(labware_file)
    # tip_one_300 = protocol.load_labware_from_definition(
    #     labware_def_tips,   #variable derived from opening json
    #     1,                  #deck position
    #     '300tips')          #custom name

    # Tube_racks & plates
    ##### !!! OPTION 1: ROBOT
    source_tube = protocol.load_labware(
        'eppendorfscrewcap_15_tuberack_5000ul',  #labware def
        2,  #deck position
        'source_tube')  #custom name
    strips_1 = protocol.load_labware(
        'pcrstrips_96_wellplate_200ul',  #labware definition
        7,  #deck position
        'strips_1')  #custom name
    strips_2 = protocol.load_labware(
        'pcrstrips_96_wellplate_200ul',  #labware definition
        4,  #deck position
        'strips_2')  #custom name
    strips_3 = protocol.load_labware(
        'pcrstrips_96_wellplate_200ul',  #labware definition
        8,  #deck position
        'strips_3')  #custom name
    strips_4 = protocol.load_labware(
        'pcrstrips_96_wellplate_200ul',  #labware definition
        5,  #deck position
        'strips_4')  #custom name
    ##### !!! OPTION 2: SIMULATOR
    # with open("labware/eppendorfscrewcap_15_tuberack_5000ul/"
    #             "eppendorfscrewcap_15_tuberack_5000ul.json") as labware_file:
    #           labware_def_5mL = json.load(labware_file)
    # source_tube = protocol.load_labware_from_definition(
    #     labware_def_5mL,          #variable derived from opening json
    #     2,                        #deck position
    #     'source_tube')            #custom name
    # with open("labware/pcrstrips_96_wellplate_200ul/"
    #           "pcrstrips_96_wellplate_200ul.json") as labware_file:
    #         labware_def_pcrstrips = json.load(labware_file)
    # strips_1 = protocol.load_labware_from_definition(
    #     labware_def_pcrstrips,    #variable derived from opening json
    #     7,                        #deck position
    #     'strips_1')               #custom name
    # strips_2 = protocol.load_labware_from_definition(
    #     labware_def_pcrstrips,    #variable derived from opening json
    #     4,                        #deck position
    #     'strips_2')               #custom name
    # strips_3 = protocol.load_labware_from_definition(
    #     labware_def_pcrstrips,    #variable derived from opening json
    #     8,                        #deck position
    #     'strips_3')               #custom name
    # strips_4 = protocol.load_labware_from_definition(
    #     labware_def_pcrstrips,    #variable derived from opening json
    #     5,                        #deck position
    #     'strips_4')               #custom name

    # Pipettes
    p300 = protocol.load_instrument(
        'p300_single_gen2',  #instrument definition
        'right',  #mount position
        tip_racks=[tip_one_300])  #assigned tiprack
    # =============================================================================

    # ==========================VARIABLES TO SET#!!!===============================
    # =============================================================================
    start_vol = 3000
    ## The start_vol is the volume (ul) that is in the source labware at  ##
    ## the start of the protocol.                                         ##
    dispension_vol = 30
    ## The dispension_vol is the volume (ul) that needs to be aliquoted   ##
    ## into the destination wells/tubes.                                  ##
    p300.starting_tip = tip_one_300.well('A1')
    ## The starting_tip is the location of first pipette tip in the box   ##
    container = 'tube_5mL'
    ## The container variable is needed for the volume tracking module.   ##
    ## It tells the module which dimensions to use for the calculations   ##
    ## of the pipette height. It is the source labware from which liquid  ##
    ## is aliquoted.                                                      ##
    ## There are several options to choose from:                          ##
    ## 'tube_1.5ml', 'tube_2mL', 'tube_5mL', 'tube_15mL', 'tube_50mL'   	##
    source = source_tube['C1']
    # Destination wells============================================================
    destinations = []
    ## Create an empty list to append wells to                            ##
    destination_columns = ([
        strips_1.columns_by_name()[column_name]
        for column_name in ['2', '7', '11']
    ] + [
        strips_2.columns_by_name()[column_name]
        for column_name in ['2', '7', '11']
    ] + [
        strips_3.columns_by_name()[column_name]
        for column_name in ['2', '7', '11']
    ] + [
        strips_4.columns_by_name()[column_name]
        for column_name in ['2', '7', '11']
    ])
    ## Make a list of columns, this is a list of lists!                   ##
    for column in destination_columns:
        for well in column:
            destinations.append(well)
# =============================================================================

# ==========================PREDIFINED VARIABLES===============================
# =============================================================================
    aspiration_vol = dispension_vol
    ## The aspiration_vol is the volume (ul) that is aspirated from the   ##
    ## container.                                                         ##
    ##### Variables for volume tracking
    start_height = vt.cal_start_height(container, start_vol)
    ## Call start height calculation function from volume tracking module.##
    current_height = start_height
    ## Set the current height to start height at the beginning of the     ##
    ## protocol.                                                          ##
    # =============================================================================

    # =================================ALIQUOTING==================================
    # =============================================================================
    ## For each column in destination_wells, pick up a tip, than for each   ##
    ## well in these columns pipette mix, and after the+ column drop the tip##
    ## Repeat untill all columns in the list are done.                      ##
    for well in destinations:
        ## Name all the wells in the plate 'well', for all these do:            ##
        p300.pick_up_tip()
        current_height, pip_height, bottom_reached = vt.volume_tracking(
            container, dispension_vol, current_height)
        ## The volume_tracking function needs the arguments container,    ##
        ## dispension_vol, and the current_height which we have set in    ##
        ## this protocol. With those variables, the function updates      ##
        ## the current_height, the pip_height and calculates the          ##
        ## delta_height of the liquid after the next aspiration step.     ##
        if bottom_reached:
            aspiration_location = source.bottom(z=1)  #!!!
            protocol.comment("You've reached the bottom!")
        else:
            aspiration_location = source.bottom(pip_height)  #!!!
        ## If the level of the liquid in the next run of the loop will    ##
        ## be smaller than 1 we have reached the bottom of the tube.      ##
        ## To prevent the pipette from crashing into the bottom, we       ##
        ## tell it to go home and pause the protocol so that this can     ##
        ## never happen. Set the location of where to aspirate from.      ##
        ## Because we put this in the loop, the location will change      ##
        ## to the newly calculated height after each pipetting step.      ##
        p300.aspirate(aspiration_vol, aspiration_location)
        ## Aspirate the amount specified in aspiration_vol from the       ##
        ## location specified in aspiration_location.                     ##
        p300.dispense(dispension_vol, well)
        ## Dispense the amount specified in dispension_vol to the         ##
        ## location specified in well (so a new well every time the       ##
        ## loop restarts)                                                 ##
        p300.drop_tip()


# =============================================================================
Example #5
0
File: drop.py Project: dn440/PPP-OT
def run(protocol: protocol_api.ProtocolContext):
	tiprack1 = protocol.load_labware("opentrons_96_tiprack_20ul",'1')
	p20 = protocol.load_instrument('p20_single_gen2',"right",tip_racks=[tiprack1])
	p20.pick_up_tip()
	p20.drop_tip()
Example #6
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_10,
        std_11, std_12, std_13, std_14, std_15
    ]
    std_conc = [
        std_4,
        std_5,
        std_6,
        std_7,
        std_8,
    ]
    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[0:2]:
        p20.pick_up_tip()
        for row in rows:
            p20.aspirate(18, mmp_tube)
            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(6, std_conc[count])  #take from standand
        p20.touch_tip()
        for col in cols[0:2]:
            p20.dispense(2, holder_1[row + str(col)])  # dispense in PCR tubes
            p20.touch_tip()
        p20.dispense(2, waste)
        p20.blow_out(waste)
        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(4, std_conc[count])
        p20.touch_tip()
        for col in cols[0:1]:
            p20.dispense(2, holder_1[row + str(col)])
            p20.touch_tip()
        p20.dispense(2, waste)
        p20.blow_out(waste)
        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(8, std_conc[count])
        p20.touch_tip()
        for col in cols[1:2]:
            p20.dispense(2, holder_1[row + str(col)])
            p20.touch_tip()
        p20.dispense(2, waste)
        p20.blow_out(waste)
        p20.drop_tip()

    # add water to last 3 wells
    for row in rows[7:8]:
        p20.pick_up_tip()
        p20.aspirate(4, water)
        p20.touch_tip()
        for col in cols[1:2]:
            p20.dispense(2, holder_1[row + str(col)])
            p20.touch_tip()
        p20.dispense(2, waste)
        p20.blow_out(waste)
        p20.drop_tip()
def run(ctx: protocol_api.ProtocolContext):
    STEP = 0
    STEPS = {  # Dictionary with STEP activation, description and times
        1: {'Execute': True,    'description': 'Transferir muestras al deepwell ('+str(VOLUME_SAMPLE)+' ul)'},
    }

    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
    if not ctx.is_simulating():
        folder_path = '/var/lib/jupyter/notebooks/' + run_id
        if not os.path.isdir(folder_path):
            os.mkdir(folder_path)
        file_path = folder_path + '/Station_A_time_log.txt'

    # Define Reagents as objects with their properties
    class Reagent:
        def __init__(self, name, flow_rate_aspirate, flow_rate_dispense,
                     delay):
            self.name = name
            self.flow_rate_aspirate = flow_rate_aspirate
            self.flow_rate_dispense = flow_rate_dispense
            self.delay = delay

    class Reagent2:
        def __init__(self,
                     name,
                     flow_rate_aspirate,
                     flow_rate_dispense,
                     reagent_reservoir_volume,
                     delay,
                     num_wells,
                     tip_recycling='none'):
            self.name = name
            self.flow_rate_aspirate = flow_rate_aspirate
            self.flow_rate_dispense = flow_rate_dispense
            self.reagent_reservoir_volume = reagent_reservoir_volume
            self.delay = delay
            self.num_wells = num_wells
            self.col = 0
            self.vol_well = 0
            self.tip_recycling = tip_recycling
            self.vol_well_original = reagent_reservoir_volume / num_wells

    # Reagents and their characteristics
    Samples = Reagent(name='Samples',
                      flow_rate_aspirate=50,
                      flow_rate_dispense=100,
                      delay=0)

    Lysis = Reagent2(name='Lysis',
                     flow_rate_aspirate=50,
                     flow_rate_dispense=100,
                     reagent_reservoir_volume=48000,
                     num_wells=1,
                     delay=0)

    ctx.comment(' ')
    ctx.comment('###############################################')
    ctx.comment('VALORES DE VARIABLES')
    ctx.comment(' ')
    ctx.comment('Número de muestras: ' + str(NUM_SAMPLES))
    ctx.comment('Número de ciclos de recogida (pools): ' + str(NUM_POOLS))
    ctx.comment('Volumen de muestra a mover: ' + str(VOLUME_SAMPLE) + ' ul')
    ctx.comment('Foto-sensible: ' + str(PHOTOSENSITIVE))
    ctx.comment(' ')
    ctx.comment('###############################################')
    ctx.comment('VOLÚMENES PARA ' + str(NUM_SAMPLES) + ' MUESTRAS')
    ctx.comment(' ')
    ctx.comment('###############################################')
    ctx.comment(' ')

    ##################
    # Custom functions
    def move_vol_multichannel(pipet, reagent, source, dest, vol, air_gap_vol,
                              x_offset, pickup_height, 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
        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
        '''
        # SOURCE
        s = source.bottom(pickup_height).move(Point(x=x_offset[0]))
        pipet.aspirate(vol, s,
                       rate=reagent.flow_rate_aspirate)  # 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=-10)

    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 custom_mix(pipet,
                   reagent,
                   location,
                   vol,
                   rounds,
                   blow_out,
                   mix_height,
                   x_offset,
                   source_height=5,
                   touch_tip=False):
        '''
        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
        if touch_tip == True:
            pipet.touch_tip(speed=20, v_offset=-10)

    def generate_source_table(source, source_extra):
        '''
        Concatenate the wells frome the different origin racks
        '''
        num_cols = math.ceil(NUM_SAMPLES / 9)
        s = []
        for i in range(num_cols):
            if i < 5:
                s += source[0].columns()[i] + source[1].columns(
                )[i] + source[2].columns()[i]
            else:
                s += source[3].columns()[i - 5] + source[4].columns()[
                    i - 5] + source[5].columns()[i - 5]

        return s

    def distribute_custom(pipette,
                          reagent,
                          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),
                         rate=reagent.flow_rate_aspirate)
        pipette.move_to(src.top(z=5))
        pipette.aspirate(air_gap_vol_sample,
                         rate=reagent.flow_rate_aspirate)  # air gap
        for d in dest:
            pipette.dispense(volume + air_gap_vol_sample,
                             d.top(),
                             rate=reagent.flow_rate_dispense)
            pipette.move_to(d.top(z=5))
            pipette.aspirate(air_gap_vol_sample,
                             rate=reagent.flow_rate_dispense)  # air gap
        try:
            pipette.blow_out(waste_pool.wells()[0].bottom(pickup_height + 3))
        except:
            pipette.blow_out(waste_pool.top(pickup_height + 3))
        return (len(dest) * volume)

    def pick_up_tip(pip, tips):
        nonlocal tip_track
        #if not ctx.is_simulating():
        if recycle_tip:
            pip.pick_up_tip(tips[0].wells()[0])
        else:
            if tip_track['counts'][pip] >= tip_track['maxes'][pip]:
                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.pause('Cambiar ' + str(pip.max_volume) +
                          ' µl tipracks antes del pulsar Resume.')
                pip.reset_tipracks()
                tip_track['counts'][pip] = 0
                tip_track['num_refills'][pip] += 1
            pip.pick_up_tip()

    def drop_tip(pip):
        if recycle_tip == True:
            pip.return_tip()
        else:
            pip.drop_tip(home_after=False)
        tip_track['counts'][pip] += 8 if '8-Channel' in str(pip) else 1

    def start_run():
        ctx.comment(' ')
        ctx.comment('###############################################')
        ctx.comment('Empezando protocolo')
        if PHOTOSENSITIVE == False:
            ctx._hw_manager.hardware.set_lights(button=True, rails=True)
        else:
            ctx._hw_manager.hardware.set_lights(button=True, rails=False)
        now = datetime.now()
        # dd/mm/YY H:M:S
        start_time = now.strftime("%Y/%m/%d %H:%M:%S")
        return start_time

    def finish_run():
        ctx.comment('###############################################')
        ctx.comment('Protocolo finalizado')
        ctx.comment(' ')
        #Set light color to blue
        ctx._hw_manager.hardware.set_lights(button=True, rails=False)
        now = datetime.now()
        # dd/mm/YY H:M:S
        finish_time = now.strftime("%Y/%m/%d %H:%M:%S")
        if PHOTOSENSITIVE == False:
            for i in range(10):
                ctx._hw_manager.hardware.set_lights(button=False, rails=False)
                time.sleep(0.3)
                ctx._hw_manager.hardware.set_lights(button=True, rails=True)
                time.sleep(0.3)
        else:
            for i in range(10):
                ctx._hw_manager.hardware.set_lights(button=False, rails=False)
                time.sleep(0.3)
                ctx._hw_manager.hardware.set_lights(button=True, rails=False)
                time.sleep(0.3)
        ctx._hw_manager.hardware.set_lights(button=True, rails=False)

        ctx.comment('Puntas de  200 ul utilizadas: ' +
                    str(tip_track['counts'][m300]) + ' (' +
                    str(round(tip_track['counts'][m300] / 96, 2)) +
                    ' caja(s))')
        ctx.comment('Puntas de 1000 ul utilizadas: ' +
                    str(tip_track['counts'][p1000]) + ' (' +
                    str(round(tip_track['counts'][p1000] / 96, 2)) +
                    ' caja(s))')
        ctx.comment('###############################################')

        return finish_time

    def log_step_start():
        ctx.comment(' ')
        ctx.comment('###############################################')
        ctx.comment('PASO ' + str(STEP) + ': ' + STEPS[STEP]['description'])
        ctx.comment('###############################################')
        ctx.comment(' ')
        return datetime.now()

    def log_step_end(start):
        end = datetime.now()
        time_taken = (end - start)
        STEPS[STEP]['Time:'] = str(time_taken)

        ctx.comment(' ')
        ctx.comment('Paso ' + str(STEP) + ': ' + STEPS[STEP]['description'] +
                    ' hizo un tiempo de ' + str(time_taken))
        ctx.comment(' ')

    ####################################
    # load labware and modules
    ####################################
    if NUM_SAMPLES <= 45:
        rack_num = 3
        ctx.comment('Los racks a utilizar son: ' + str(rack_num))
    else:
        rack_num = 6
        ctx.comment('Los racks a utilizar son: ' + str(rack_num))

    source_racks = [
        ctx.load_labware('opentrons_15_tuberack_falcon_15ml_conical', slot,
                         'Source Tube Rack with snapcap ' + str(i + 1))
        for i, slot in enumerate(['7', '4', '1', '8', '5', '2'][:rack_num])
    ]

    source_racks_extra = ctx.load_labware(
        'opentrons_10_tuberack_falcon_4x50ml_6x15ml_conical', '9',
        'Lysis Tube Rack')

    Lysis.reagent_reservoir = source_racks_extra.wells_by_name()['A3']

    ##################################
    # Destination plate
    dest_deepwell_plate = ctx.load_labware('nest_96_wellplate_2ml_deep', '6',
                                           'NEST 96 Deepwell Plate 2mL')

    ####################################
    # Load tip_racks
    tips1000 = [
        ctx.load_labware('opentrons_96_filtertiprack_1000ul', slot,
                         '1000µl filter tiprack') for slot in ['11']
    ]

    tips300 = [
        ctx.load_labware('opentrons_96_filtertiprack_200ul', slot,
                         '200µl filter tiprack') for slot in ['10']
    ]

    ################################################################################
    # Setup sources and destinations
    sources_sample = generate_source_table(source_racks,
                                           source_racks_extra)[0:NUM_SAMPLES]

    dests_deepwell = dest_deepwell_plate.wells()[0:NUM_SAMPLES]

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

    tip_track = {
        'counts': {
            m300: 0,
            p1000: 0
        },
        'maxes': {
            m300: 96 * len(m300.tip_racks),
            p1000: 96 * len(p1000.tip_racks)
        },  #96 tips per tiprack * number or tipracks in the layout
        'num_refills': {
            m300: 0,
            p1000: 0
        }
    }

    # used tip counter and set maximum tips available

    start_run()

    ############################################################################
    # STEP 1: ADD SAMPLES TO DEEPWELL
    ############################################################################
    STEP += 1
    if STEPS[STEP]['Execute'] == True:
        start = log_step_start()

        for pool in range(NUM_POOLS):
            for s, d in zip(sources_sample, dests_deepwell):
                if not p1000.hw_pipette['has_tip']:
                    pick_up_tip(p1000, tips1000)

                move_vol_multichannel(p1000,
                                      reagent=Samples,
                                      source=s,
                                      dest=d,
                                      vol=VOLUME_SAMPLE,
                                      air_gap_vol=air_gap_vol_sample,
                                      x_offset=x_offset,
                                      pickup_height=4,
                                      disp_height=-10,
                                      blow_out=True,
                                      touch_tip=False)
                p1000.air_gap(air_gap_vol_sample)

                drop_tip(p1000)

                #pausar
                if pool < NUM_POOLS - 1:
                    ctx.pause(
                        'Cambiar las muestras para el pooling y cambiar el tipRacks de 1000 µl antes del pulsar Resume.'
                    )

        log_step_end(start)

    # 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()

    ############################################################################
    finish_run()
def run(protocol: protocol_api.ProtocolContext):
    #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)
    tiprack2 = 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, tiprack2]
    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")

    #RUN SETTINGS
    runColumns = 2  # 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.
    mixdownReps = 10
    mixMovementReps = 10

    #Mixing settings
    washMixing = 100  # volume (ul)
    waterMixing = 25  # volume (ul)
    mixingOffset = 1  # Positive values mean to the right. Relative to center (mm)
    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", "A2", "A3", "A4", "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):
        """
        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)
            print("Only %s minutes more! Hold in there!" % time)

    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 clean_tips(pipette, dump):
        protocol.delay(seconds=2)
        meneillo(
            pipette, dump.top(topOffset)
        )  #In case something is TheOppositeOfDense and just drips down
        pipette.dispense(
            20
        )  #Make sure we expel everything that must be expelled. We dont want to move droplets around.

    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,
                 repsdown=mixdownReps,
                 repsmovement=mixMovementReps,
                 yOffset=0.75,
                 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
        for _ in range(repsdown):
            p300.aspirate(
                vol,
                loc.bottom().move(
                    types.Point(x=0 + moveSide, y=yOffset, z=bottomHeight)))
            p300.dispense(
                vol,
                loc.bottom().move(
                    types.Point(x=0 + moveSide, y=yOffset, z=bottomHeight)))
            yOffset = -yOffset
        for _ in range(repsmovement):
            p300.aspirate(
                vol,
                loc.bottom().move(
                    types.Point(x=0 + moveSide, y=yOffset, z=bottomHeight)))
            yOffset = -yOffset
            p300.dispense(
                vol,
                loc.bottom().move(
                    types.Point(x=0 + moveSide, y=yOffset, z=height)))
        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,
                           newtip=False):
        """
        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):
            if (ID == "A2" or ID == "A4"):
                blabla = 1
            else:
                blabla = -1
            if newtip == False:
                currentip = parkingRack[ID]
            else:
                currentip = availableTips.pop()
            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=blabla, 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=blabla, y=0, z=bottomHeight)),
                          dump.top(topOffset),
                          new_tip="never")
            clean_tips(pipette, dump)
            remove_tip(pipette, currentip)
        p300.flow_rate.aspirate = 50

    def slow_transfer(vol,
                      reagent,
                      columnID,
                      reagentName,
                      mixVol=washMixing,
                      downRepeats=mixdownReps,
                      movementRepeats=mixMovementReps,
                      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,
                    repsdown=0,
                    repsmovement=beadsMixRepeats,
                    yOffset=0,
                    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)
            if (ID == "A2" or ID == "A4"):
                well_mix(vol=mixVol,
                         loc=to,
                         repsdown=downRepeats,
                         repsmovement=movementRepeats,
                         moveSide=-mixingOffset,
                         height=altura)
            else:
                well_mix(vol=mixVol,
                         loc=to,
                         repsdown=downRepeats,
                         repsmovement=movementRepeats,
                         moveSide=mixingOffset,
                         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,
                  downRepeats=0,
                  movementRepeats=20)
    #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,
                  downRepeats=0,
                  movementRepeats=20)
    #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)
    #INCUBATION 3: 5 min incubation with magnet [Total: 20 min]

    #STEP 3: Remove magnetic beads supernatant
    remove_supernatant(vol=initialSupernatant + 20.5,
                       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"
        % str(incubationDry / 2))
    clock(time=incubationDry / 2)
    remove_supernatant(vol=20,
                       wasteID="A4",
                       reagentName="Dried ethanol",
                       columnID=columnID,
                       newtip=True)
    protocol.comment(
        "Making sure I removed all the ethanol. Now incubating again for %s min"
        % str(incubationDry / 2))
    clock(time=incubationDry / 2)

    #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,
                  removalStepAfter=False)  #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):
        if (ID == "A2"):
            hahas = 1
        else:
            hahas = -1
        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=hahas, 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!")
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 = 200  # 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 = 800  # F primer at highest concentration. (in nM)
    F_mid = 600  # What is the constant F primer concentration for standards? This should be guess or from literature or empirically determined. (in nM)
    F_low = 200  # F primer at concentration. (in nM)
    R_upp = 800  # R primer at lowest concentration. (in nM)
    R_mid = 600  # What is the constant R primer concentration for standards? This should be guess or from literature or empirically determined. (in nM)
    R_low = 200  # 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)
    print("dna_XFR_samp_int", dna_XFR_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
    p300.transfer(
        dna_XFR_samp_int,  # ~55.2
        std_2.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),
        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(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(15))  # 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(6, 200, tube.bottom(10))
        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(3))
            p300.flow_rate.aspirate = 40
            p300.flow_rate.dispense = 20
            p300.mix(1, 70,
                     plate[swell].bottom(2))  #slow mix to avoid/remove bubbles
            p300.blow_out(plate[swell].bottom(6))
            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()
Example #10
0
def run(ctx: protocol_api.ProtocolContext):

    # Init protocol run
    run = ProtocolRun(ctx)

    minutos = 1  # Tendria que ser 60 pero para testeo lo pongo a 10
    run.add_step(description="65C Incubation",
                 wait_time=5 * minutos)  # 5* 60 minutos 1
    run.add_step(description="Transfer From temperature to magnet 485ul")  # 2
    run.add_step(description="Magnetic on: 10 minutes",
                 wait_time=10 * minutos)  # 10*60 3
    run.add_step(
        description="Extraer liquido no beads. Slot 7 - Piscina Slot 3")  # 4
    run.add_step(description="Magnetic off")  # 5
    run.add_step(
        description=
        "Replace tips, add WB, add ETOH, vaciar piscina y trash. Cambiar nuevo DW SLOT 10"
    )  # INTERACTION 6

    # Add WB
    run.add_step(description="Add 500ul de WB  a los beats Slot 4 - 7 ")  # 7
    run.add_step(description="Magnetic on: 2 minutes",
                 wait_time=2 * minutos)  # 2*60 8
    run.add_step(description="Extraer liquido no beats. Slot 7 - Slot 3")  # 9
    run.add_step(description="Magnetic off")  # 10

    # Add ETOH First step
    run.add_step(description="Add 500ul de etoh a los beats Slot 8 - 7 ")  # 11
    run.add_step(description="Magnetic on: 2 minutes",
                 wait_time=2 * minutos)  # 2*60 12
    run.add_step(description="Extraer liquido no beats. Slot 7 - Slot 3")  # 13
    run.add_step(description="Magnetic off")  # 14

    run.add_step(description="Replace tips etc. add elution")
    # Add ETOH Second step
    run.add_step(description="Add 250ul de etoh a los beats Slot 8 - 7 ")  # 15
    run.add_step(description="Magnetic on: 2 minutes",
                 wait_time=2 * minutos)  # 2*60 16
    run.add_step(description="Extraer liquido no beats. Slot 7 - Slot 3")  # 17
    run.add_step(description="Secar durante 10 minutos",
                 wait_time=10)  # 10 * 60 18
    run.add_step(description="Magnetic off")  # 19
    run.add_step(
        description="Add elution move to temperature same tip 4 -> 7 -> 10"
    )  # 20
    run.add_step(description="65C Incubation 10'",
                 wait_time=10)  # 10 * 60 # 21

    run.add_step(description="Replace tips, change deepwell slot 7 magnet")
    run.add_step(description="Move 50ul from temp to magnet 10-7")  # 22
    run.add_step(description="Magnetic on: 3 minutes",
                 wait_time=3 * minutos)  #23 3 * 60 27
    run.add_step(description="Move 50ul Magnet Final destination 7-> 2")  # 24
    run.add_step(description="Magnetic off")  # 25

    # execute avaliaible steps
    run.init_steps(steps)

    ##################################
    # Define desk
    moving_type = "axygen_96_wellplate_2000ul"
    moving_type_sim = "biorad_96_wellplate_200ul_pcr"

    # Destination plate SLOT 2
    try:
        aw_slot = ctx.load_labware(moving_type, 2)
    except:
        moving_type = moving_type_sim
        aw_slot = ctx.load_labware(moving_type, 2)

    aw_wells = aw_slot.wells()[:NUM_SAMPLES]
    aw_wells_multi = aw_slot.rows()[0][:num_cols]

    wbeb_slot = ctx.load_labware('nest_12_reservoir_15mL', 4)
    wbeb_wells_multi = wbeb_slot.rows()[0][:num_cols]

    #Set up trash1
    trash_pool_slot = ctx.load_labware('nest_1_reservoir_195ml', 3)
    trash_pool_wells_multi = trash_pool_slot.rows()[0][:num_cols]

    # # Magnetic module plus NEST_Deep_well_reservoire
    magdeck = ctx.load_module('magnetic module gen2', 7)
    magdeck.disengage()
    mag_slot = magdeck.load_labware(moving_type)
    mag_wells_multi = mag_slot.rows()[0][:num_cols]

    # Ethanol Pool
    etoh_slot = ctx.load_labware('nest_1_reservoir_195ml', 1)
    etoh_wells_multi = etoh_slot.rows()[0][:num_cols]

    # Temperature module plus NEST_Deep_well_reservoire
    tempdeck = ctx.load_module('tempdeck', 10)
    temp_slot = tempdeck.load_labware(moving_type)
    temp_wells_multi = temp_slot.rows()[0][:num_cols]

    # Mount pippets and set racks
    tips300_8 = ctx.load_labware('opentrons_96_filtertiprack_200ul', "8")
    tips300_9 = ctx.load_labware('opentrons_96_filtertiprack_200ul', "9")
    tips300_6 = ctx.load_labware('opentrons_96_filtertiprack_200ul', "6")
    tips300_5 = ctx.load_labware('opentrons_96_filtertiprack_200ul', "5")

    #run.mount_right_pip('p20_single_gen2', tip_racks=[tips20], capacity=20)
    run.mount_left_pip('p300_multi_gen2',
                       tip_racks=[tips300_8, tips300_9, tips300_6, tips300_5],
                       capacity=200,
                       multi=True)

    run.set_pip("left")
    ############################################################################
    # STEP 1: Incubation at 65ºC
    ############################################################################
    if (run.next_step()):
        if (set_temp_on):
            tempdeck.set_temperature(temperature)
        run.finish_step()
        tempdeck.deactivate()

    ############################################################################
    # STEP 2: Transfer From temperature to magnet 485ul
    ############################################################################
    if (run.next_step()):

        run.set_pip("left")  # p300 multi
        liquid = Reagent(
            name='MIX_HOT',
            num_wells=1,  # change with num samples
            delay=0,
            flow_rate_aspirate=3,  # Original 0.5
            flow_rate_dispense=3,  # Original 1
            flow_rate_aspirate_mix=15,
            flow_rate_dispense_mix=25,
            reagent_reservoir_volume=485,
            h_cono=4,
            v_fondo=4 * math.pi * 4**3 / 3)

        air_gap_vol = 3
        disposal_height = -5
        pickup_height = 1

        for source, destination in zip(temp_wells_multi, mag_wells_multi):
            run.pick_up()
            run.move_volume(reagent=liquid,
                            source=source,
                            dest=destination,
                            vol=175,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height,
                            rinse=True,
                            touch_tip=True)
            run.move_volume(reagent=liquid,
                            source=source,
                            dest=destination,
                            vol=175,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height,
                            rinse=True,
                            touch_tip=True)
            run.move_volume(reagent=liquid,
                            source=source,
                            dest=destination,
                            vol=135,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height,
                            rinse=True,
                            touch_tip=True)
            run.drop_tip()

        run.finish_step()

    ############################################################################
    # STEP 3: Magnet on 10 minutos
    ############################################################################
    if (run.next_step()):
        if (set_mag_on):
            magdeck.engage(height=mag_height)
        run.finish_step()

    # Extraer liquido sin tocar los beats. Slot 7 - Piscina Slot 3
    def move_magnet_to_trash(move_vol_steps=3):
        run.set_pip("left")  # p300 multi
        # Sobre nadante primer paso
        liquid = Reagent(
            name='Sobrenadante',
            num_wells=1,  # change with num samples
            delay=0,
            flow_rate_aspirate=0.2,  # Original 0.5
            flow_rate_dispense=3,  # Original 1
            reagent_reservoir_volume=528,
            h_cono=4,
            v_fondo=4 * math.pi * 4**3 / 3)

        air_gap_vol = 3
        pickup_height = 1
        disposal_height = 0
        # Hay que revisar los offsets para el movimiento este
        for source in mag_wells_multi:
            destination = trash_pool_wells_multi[0]
            # Replace this
            run.pick_up()
            run.move_volume(reagent=liquid,
                            source=source,
                            dest=destination,
                            vol=175,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height)

            # Patch for last step of etho 250ul instead of 500
            if (move_vol_steps == 3):
                run.move_volume(reagent=liquid,
                                source=source,
                                dest=destination,
                                vol=175,
                                air_gap_vol=air_gap_vol,
                                pickup_height=pickup_height,
                                disp_height=disposal_height)

            # We want to empty does not matter if we aspirate more
            run.move_volume(reagent=liquid,
                            source=source,
                            dest=destination,
                            vol=175,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height)
            run.drop_tip()

    ############################################################################
    # STEP 4: Extract liquid from magnet to liquid trash
    ############################################################################
    if (run.next_step()):
        move_magnet_to_trash()
        run.finish_step()

    ############################################################################
    # STEP 5: Magnet off
    ############################################################################
    if (run.next_step()):
        magdeck.disengage()
        run.finish_step()

    ############################################################################
    # STEP 6: Pause to replace
    ############################################################################
    if (run.next_step()):
        run.blink()
        ctx.pause(
            'Replace tips, add WB, add ETOH, vaciar piscina y trash. Cambiar nuevo DW SLOT 10'
        )
        run.reset_pip_count(run.get_current_pip())
        run.finish_step()

    ############################################################################
    # STEP 7: Add 500ul de WB a los bits 4 - 7
    ############################################################################
    if (run.next_step()):
        run.set_pip("left")  # p300 multi
        vol_wb = 485
        wb = Reagent(
            name='WB Wash buffer',
            flow_rate_aspirate=0.25,
            flow_rate_dispense=0.25,
            flow_rate_dispense_mix=0.25,
            flow_rate_aspirate_mix=0.25,
            delay=1,
            reagent_reservoir_volume=vol_wb * (NUM_SAMPLES + 1) * 1.1,
            h_cono=1.95,
            v_fondo=695,
        )

        run.comment(wb.get_volumes_fill_print(), add_hash=True)
        wb.set_positions(wbeb_slot.rows()[0][0:wb.num_wells])

        air_gap_vol = 3
        disposal_height = -1  # Arriba y el último paso lo hacemos dentro
        pool_area = 8.3 * 71.1

        for destination in mag_wells_multi:
            run.pick_up()

            pickup_height = wb.calc_height(pool_area, 175 * 8)

            run.move_volume(reagent=liquid,
                            source=wb.get_current_position(),
                            dest=destination,
                            vol=175,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height)
            pickup_height = wb.calc_height(pool_area, 175 * 8)

            run.move_volume(reagent=liquid,
                            source=wb.get_current_position(),
                            dest=destination,
                            vol=175,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height)

            # This will be drop inside
            pickup_height = wb.calc_height(pool_area, 175 * 8)

            disposal_height = 2
            run.move_volume(reagent=liquid,
                            source=wb.get_current_position(),
                            dest=destination,
                            vol=135,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height - 3)

            run.custom_mix(liquid,
                           location=destination,
                           vol=50,
                           rounds=10,
                           blow_out=True,
                           mix_height=0)
            run.drop_tip()

        run.finish_step()

    ############################################################################
    # STEP 8: Magnet on 2 minutos
    ############################################################################
    if (run.next_step()):
        if (set_mag_on):
            magdeck.engage(height=mag_height)
        run.finish_step()
    ############################################################################
    # STEP 9: Extract liquid from magnet to liquid trash
    ############################################################################
    if (run.next_step()):
        move_magnet_to_trash()
        run.finish_step()

    ############################################################################
    # STEP 10: Magnet off
    ############################################################################
    if (run.next_step()):
        magdeck.disengage()
        run.finish_step()

    # Used twice in the next steps

    vol_etoh = 500 + 250
    etoh = Reagent(name='ETOH',
                   flow_rate_aspirate=1,
                   flow_rate_dispense=1,
                   flow_rate_dispense_mix=4,
                   flow_rate_aspirate_mix=4,
                   delay=1,
                   reagent_reservoir_volume=vol_etoh * (NUM_SAMPLES + 1),
                   vol_well_max=195000,
                   rinse=True,
                   num_wells=1,
                   h_cono=1.95,
                   v_fondo=695)

    run.comment(etoh.get_volumes_fill_print(), add_hash=True)

    ############################################################################
    # STEP 11: Add 500ul de etoh a los beats Slot 8 - 7
    ############################################################################
    if (run.next_step()):

        run.set_pip("left")  # p300 multi
        liquid = etoh
        air_gap_vol = 3
        disposal_height = -1  # Arriba y el último paso lo hacemos dentro
        pickup_height = 1

        for source, destination in zip(etoh_wells_multi, mag_wells_multi):
            run.pick_up()
            run.move_volume(reagent=liquid,
                            source=source,
                            dest=destination,
                            vol=175,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height)
            run.move_volume(reagent=liquid,
                            source=source,
                            dest=destination,
                            vol=175,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height)

            # This will be drop inside
            run.move_volume(reagent=liquid,
                            source=source,
                            dest=destination,
                            vol=135,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height - 3)

            run.custom_mix(liquid,
                           location=destination,
                           vol=50,
                           rounds=5,
                           blow_out=True,
                           mix_height=0)

            run.drop_tip()
        run.finish_step()

    ############################################################################
    # STEP 12: Magnet on 10 minutos
    ############################################################################
    if (run.next_step()):
        if (set_mag_on):
            magdeck.engage(height=mag_height)
        run.finish_step()
    ############################################################################
    # STEP 13: Extract liquid from magnet to liquid trash
    ############################################################################
    if (run.next_step()):
        move_magnet_to_trash()
        run.finish_step()

    ############################################################################
    # STEP 14   : Magnet off
    ############################################################################
    if (run.next_step()):
        magdeck.disengage()
        run.finish_step()

    ############################################################################
    # STEP 15: Run pause
    ############################################################################
    if (run.next_step()):
        run.blink()
        ctx.pause('Replace tips,add elution')
        run.reset_pip_count(run.get_current_pip())
        run.finish_step()

    ############################################################################
    # STEP 16: Add 250 de etoh a los beats Slot 8 - 7
    ############################################################################
    if (run.next_step()):

        run.set_pip("left")  # p300 multi
        liquid = etoh
        air_gap_vol = 3
        disposal_height = -1  # Arriba y el último paso lo hacemos dentro
        pickup_height = 1

        for source, destination in zip(etoh_wells_multi, mag_wells_multi):
            run.pick_up()
            run.move_volume(reagent=liquid,
                            source=source,
                            dest=destination,
                            vol=175,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height)
            # This will be drop inside
            run.move_volume(reagent=liquid,
                            source=source,
                            dest=destination,
                            vol=125,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height - 3)

            run.custom_mix(liquid,
                           location=destination,
                           vol=50,
                           rounds=5,
                           blow_out=True,
                           mix_height=0)

            run.drop_tip()

    ############################################################################
    # STEP 17: Magnet on 2 minutos
    ############################################################################
    if (run.next_step()):
        if (set_mag_on):
            magdeck.engage(height=mag_height)
        run.finish_step()

    ############################################################################
    # STEP 18: Extract liquid from magnet to liquid trash
    ############################################################################
    if (run.next_step()):
        move_magnet_to_trash(move_vol_steps=2)
        run.finish_step()

    ############################################################################
    # STEP 19: Secar durante 10 minutos
    ############################################################################
    if (run.next_step()):
        run.finish_step()
        run.blink()
        ctx.pause('Revisa que esté seco')

    ############################################################################
    # STEP 20: Magnet off
    ############################################################################
    if (run.next_step()):
        magdeck.disengage()
        run.finish_step()

    ############################################################################
    # STEP 21: Add elution move to temperature same tip 4 -> 7 -> 10
    ############################################################################
    # Used to move from temp to magnet and from magnet to destionation
    elu_beads = Reagent(
        name='BeatsToHot',
        num_wells=1,  # change with num samples
        delay=0,
        flow_rate_aspirate=3,  # Original 0.5
        flow_rate_dispense=3,  # Original 1
        flow_rate_aspirate_mix=15,
        flow_rate_dispense_mix=25,
        reagent_reservoir_volume=528,
        h_cono=4,
        v_fondo=4 * math.pi * 4**3 / 3)

    if (run.next_step()):
        # to liquid types
        vol_eb = 50
        elution = Reagent(name='Elution Buffer',
                          flow_rate_aspirate=2,
                          flow_rate_dispense=2,
                          flow_rate_dispense_mix=4,
                          flow_rate_aspirate_mix=4,
                          reagent_reservoir_volume=vol_eb * (NUM_SAMPLES + 1),
                          delay=1,
                          num_wells=1,
                          h_cono=1.95,
                          v_fondo=695,
                          rinse_loops=3)

        run.comment(elution.get_volumes_fill_print(), add_hash=True)
        elution.set_positions(wbeb_slot.rows()[0][11:12])

        air_gap_vol = 3
        disposal_height = -5
        pickup_height = 1
        for dest_source, destination in zip(mag_wells_multi, temp_wells_multi):
            run.pick_up()
            run.move_volume(reagent=elution,
                            source=elution.get_current_position(),
                            dest=dest_source,
                            vol=vol_eb,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height)

            run.custom_mix(elu_beads,
                           location=dest_source,
                           vol=100,
                           rounds=10,
                           blow_out=True,
                           mix_height=0)

            # This will be drop inside
            run.move_volume(reagent=elu_beads,
                            source=dest_source,
                            dest=destination,
                            vol=50,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height - 3)

            run.drop_tip()

        run.finish_step()

    ############################################################################
    # STEP 22: Incubation at 65ºC
    ############################################################################
    if (run.next_step()):
        if (set_temp_on):
            tempdeck.set_temperature(temperature)
        run.finish_step()

    ############################################################################
    # STEP 23: Pause to reset tips, replace deep well SLOT 7 and add DeepWell on SLOT2
    ############################################################################
    if (run.next_step()):
        run.blink()
        ctx.pause(
            'Replace tips, change DeepWell on Magnet SLOT 7, and add final Deepwell on SLOT 2'
        )
        run.reset_pip_count(run.get_current_pip())
        run.finish_step()

    ############################################################################
    # STEP 24: Move from temp to magnet
    ############################################################################
    if (run.next_step()):
        result = Reagent(
            name='Elution+magnets',
            num_wells=1,  # change with num samples
            delay=0,
            flow_rate_aspirate=3,  # Original 0.5
            flow_rate_dispense=3,  # Original 1
            flow_rate_aspirate_mix=15,
            flow_rate_dispense_mix=25,
            reagent_reservoir_volume=528,
            h_cono=4,
            v_fondo=4 * math.pi * 4**3 / 3)

        for source, destination in zip(temp_wells_multi, mag_wells_multi):
            run.pick_up()
            run.move_volume(reagent=result,
                            source=source,
                            dest=destination,
                            vol=1,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height)
            run.drop_tip()

        run.finish_step()

    ############################################################################
    # STEP 25: Magnet on 3 minutos
    ############################################################################
    if (run.next_step()):
        if (set_mag_on):
            magdeck.engage(height=mag_height)
        run.finish_step()

    ############################################################################
    # STEP 26: Move from magnet to final output slot 2
    ############################################################################
    if (run.next_step()):
        result = Reagent(
            name='Elution-magnets',
            num_wells=1,  # change with num samples
            delay=0,
            flow_rate_aspirate=3,  # Original 0.5
            flow_rate_dispense=3,  # Original 1
            flow_rate_aspirate_mix=15,
            flow_rate_dispense_mix=25,
            reagent_reservoir_volume=528,
            h_cono=4,
            v_fondo=4 * math.pi * 4**3 / 3)
        for source, destination in zip(mag_wells_multi, aw_wells_multi):
            run.pick_up()
            run.move_volume(reagent=result,
                            source=source,
                            dest=destination,
                            vol=50,
                            air_gap_vol=air_gap_vol,
                            pickup_height=pickup_height,
                            disp_height=disposal_height)
            run.drop_tip()

        run.finish_step()

    ############################################################################
    # STEP 27: Magnet off
    ############################################################################
    if (run.next_step()):
        magdeck.disengage()
        run.finish_step()

    run.log_steps_time()
    run.blink()
    ctx.comment('Finished! \nMove plate to PCR')
Example #11
0
def run(protocol: protocol_api.ProtocolContext):

    # LABWARE
    fuge_rack = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap', '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')  # 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')

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

    # REAGENTS
    #reagent_rack
    luminaseBuffer = reagent_rack[
        'B1']  #Raquel's V2 mix form 22 April 2021; 19536ul

    std_1 = fuge_rack['A1']  # 900ul Water
    std_2 = fuge_rack['A2']  # 900ul water
    std_3 = fuge_rack['A3']  # 900ul water
    std_4 = fuge_rack['A4']  # 900ul water
    std_5 = fuge_rack['A5']  # 900ul water
    std_6 = fuge_rack['A6']  # 900ul water
    std_7 = fuge_rack['B1']  # 900ul water
    std_8 = fuge_rack['B2']  # 900ul water
    std_9 = fuge_rack['B3']  # 900ul water
    std_10 = fuge_rack['B4']  # 900ul water
    std_11 = fuge_rack['B5']  # 900ul water
    std_12 = fuge_rack['B6']  # 900ul water
    std_13 = fuge_rack['C1']  # 900ul water
    std_14 = fuge_rack['C2']  # 900ul water
    std_15 = fuge_rack['C3']  # 900ul water
    water = fuge_rack['D6']
    trash = fuge_rack['C6']  # trash; receives some of the blowouts

    # lists
    dATP_vol = 15
    luminaseBuffer_vol = 185
    rows = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
    std_wells = [
        std_1, std_2, std_3, std_4, std_5, std_6, std_7, std_8, std_9, std_10,
        std_11, std_12, std_13, std_14, std_15, water
    ]

    #### COMMANDS ######
    # Add luminase buffer containing D-luciferin, reagent and water
    p300.pick_up_tip()
    sample_h = fifty_ml_heights(19536, 96,
                                185)  # volumes are different, so take median
    sample_counter = 0
    for j in range(12):  # cols 1..10 can be serviced by p200.
        for row in rows:  # process 8 rows
            dest = row + str(j + 1)
            p300.aspirate(luminaseBuffer_vol,
                          luminaseBuffer.bottom(sample_h[sample_counter]))
            p300.dispense(luminaseBuffer_vol, plate[dest].bottom(5))
            p300.blow_out(plate[dest].bottom(5))
            p300.move_to(plate[dest].bottom())
    p300.drop_tip()

    protocol.pause(
        'All reagents added but ATP for background calculations. Resume to add ATP.'
    )
    # add ATP serial dilutions
    p300.pick_up_tip()
    dATP_bolus = 5
    for j, (tube, row) in enumerate(
            zip(reversed(std_wells), reversed(2 * rows))
    ):  #forgive me; loop in reverse; keep tip for speed so low conc to high conc
        p300.aspirate(dATP_vol * 6 + dATP_bolus, tube.bottom(20))  #5ul bolus
        for i in range(6):  # process 6 rows
            dest = row + str(i + 7) if j < 8 else row + str(
                i + 1)  # going backwards, need to move to 1st half
            p300.dispense(dATP_vol, plate[dest].bottom(2))
        p300.dispense(dATP_bolus, trash.top(-4))  # remove bolus
        p300.blow_out(trash.top(-4))
        p300.touch_tip(trash, v_offset=-4)
    p300.drop_tip()
Example #12
0
    def _simulate(self):
        self._reset()

        stack = []
        res = []
        commands = []

        self._containers.clear()
        self._instruments.clear()
        self._modules.clear()
        self._interactions.clear()

        def on_command(message):
            payload = message['payload']
            description = payload.get('text', '').format(
                **payload
            )

            if message['$'] == 'before':
                level = len(stack)

                stack.append(message)
                commands.append(payload)

                res.append(
                    {
                        'level': level,
                        'description': description,
                        'id': len(res)})
            else:
                stack.pop()

        unsubscribe = self._broker.subscribe(command_types.COMMAND, on_command)

        try:
            # ensure actual pipettes are cached before driver is disconnected
            if ff.use_protocol_api_v2():
                self._hardware.cache_instruments()
                instrs = {}
                for mount, pip in self._hardware.attached_instruments.items():
                    if pip:
                        instrs[mount] = {'model': pip['model'],
                                         'id': pip.get('pipette_id', '')}
                sim = adapters.SynchronousAdapter.build(
                    API.build_hardware_simulator,
                    instrs,
                    [mod.name()
                     for mod in self._hardware.attached_modules.values()],
                    strict_attached_instruments=False)
                sim.home()
                self._simulating_ctx = ProtocolContext(self._loop,
                                                       sim,
                                                       self._broker)
                if self._is_json_protocol:
                    run_protocol(protocol_json=self._protocol,
                                 simulate=True,
                                 context=self._simulating_ctx)
                else:
                    run_protocol(protocol_code=self._protocol,
                                 simulate=True,
                                 context=self._simulating_ctx)
            else:
                self._hardware.broker = self._broker
                self._hardware.cache_instrument_models()
                self._hardware.disconnect()
                if self._is_json_protocol:
                    execute_protocol(self._protocol)
                else:
                    exec(self._protocol, {})
        finally:
            # physically attached pipettes are re-cached during robot.connect()
            # which is important, because during a simulation, the robot could
            # think that it holds a pipette model that it actually does not
            if not ff.use_protocol_api_v2():
                self._hardware.connect()
            unsubscribe()

            instruments, containers, modules, interactions = _accumulate(
                [_get_labware(command) for command in commands])

            self._containers.extend(_dedupe(containers))
            self._instruments.extend(_dedupe(instruments))
            self._modules.extend(_dedupe(modules))
            self._interactions.extend(_dedupe(interactions))

            # Labware calibration happens after simulation and before run, so
            # we have to clear the tips if they are left on after simulation
            # to ensure that the instruments are in the expected state at the
            # beginning of the labware calibration flow
            if not ff.use_protocol_api_v2():
                self._hardware.clear_tips()

        return res
Example #13
0
def run(protocol: protocol_api.ProtocolContext):
    #######################################################################################################################################
    ## SETUP

    # Load Labware
    temp_mod = protocol.load_module('Temperature Module', '9')
    reaction_plate = protocol.load_labware(
        "biorad_384_wellplate_50ul", "8",
        label="reaction plate")  # where the magic happens
    # tube_rack = protocol.load_labware("opentrons_96_aluminumblock_generic_pcr_strip_200ul", "6", label = "aluminum block") # CBS and substrate stocks
    sample_plate = protocol.load_labware(
        "greiner_96_wellplate_323ul", "6", label="sample plate"
    )  # CBS and dye stocks (!!! protect dye from light !!!)
    library_plate = protocol.load_labware(
        "greiner_96_wellplate_323ul", "5",
        label="library plate")  # compound library

    # Specify tip racks
    tiprack1 = protocol.load_labware("opentrons_96_tiprack_10ul", '2')
    tiprack2 = protocol.load_labware("opentrons_96_tiprack_300ul", '3')

    # Load pipettes and set parameters
    p10 = protocol.load_instrument("p10_multi", "right", tip_racks=[tiprack1])
    p50 = protocol.load_instrument('p50_multi', "left", tip_racks=[tiprack2])

    p10.flow_rate.aspirate = 8
    p10.flow_rate.dispense = 8
    # 384-well depth is 11.56 mm and max volume is 112 uL
    # 20 uL is 2 mm high, tandem (middle) wall is 5.1 mm high
    p10.well_bottom_clearance.dispense = 1
    p50.well_bottom_clearance.dispense = 7

    # Specify target wells (ONLY NEED TO EDIT WELLS HERE)
    samples = ["5", "6"]  # columns on sample plate with protein and dye
    cols_compounds = [6, 7, 8, 9,
                      10]  # library columns to aspirate compounds from
    cols_woSAM = [1, 2, 3, 4,
                  5]  # destination wells in reaction plate (384-tandem)
    cols_wSAM = [
        6, 7, 8, 9, 10
    ]  # destination wells in reaction plate (384-tandem) (30 uM SAM final c)
    wells_reaction_woSAM = ['A' + str(i) for i in cols_woSAM]
    wells_reaction_wSAM = ['A' + str(i) for i in cols_wSAM]
    wells_reaction = ['A' + str(i) for i in (cols_woSAM + cols_wSAM)]

    #######################################################################################################################################
    ## PROCEDURE

    # Distribute fluorescent dye from sample plate to reaction plate
    # p10.distribute(5, sample_plate.columns_by_name()[samples[2]], [reaction_plate.wells_by_name()[i] for i in wells_reaction],
    # disposal_volume = 0, blow_out = False, touch_tip = True)

    # Distribute protein mixed with fluorescent dye
    p10.distribute(
        13.5,
        sample_plate.columns_by_name()[samples[0]],
        [reaction_plate.wells_by_name()[i] for i in wells_reaction_woSAM],
        disposal_volume=0,
        blow_out=False,
        new_tip='once')
    p10.distribute(
        13.5,
        sample_plate.columns_by_name()[samples[1]],
        [reaction_plate.wells_by_name()[i] for i in wells_reaction_wSAM],
        disposal_volume=0,
        blow_out=False,
        new_tip='once')
    #p10.distribute(13.5, sample_plate.columns_by_name()[samples[1]], [reaction_plate.wells_by_name()[i] for i in wells_reaction_wSAM],
    #disposal_volume = 0, blow_out = False, new_tip = 'once', touch_tip = True)

    # Distribute compounds from 96-well library plate and mix
    vol = 1.5
    for i in range(0, len(cols_compounds)):
        p10.transfer(vol,
                     library_plate.columns_by_name()[str(cols_compounds[i])],
                     reaction_plate.wells_by_name()[wells_reaction_woSAM[i]],
                     mix_after=(3, vol))
        p10.transfer(vol,
                     library_plate.columns_by_name()[str(cols_compounds[i])],
                     reaction_plate.wells_by_name()[wells_reaction_wSAM[i]],
                     mix_after=(3, vol))
def run(ctx: protocol_api.ProtocolContext):

    # load labware
    ic_pk = ctx.load_labware(
        'opentrons_24_aluminumblock_nest_2ml_snapcap', '9',
        'chilled tubeblock for internal control and proteinase K (strip 1)'
    ).wells()[0]
    source_racks = [
        ctx.load_labware(
            'opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap', slot,
            'source tuberack ' + str(i + 1))
        for i, slot in enumerate(['1', '2', '3', '4'])
    ]
    dest_plate = ctx.load_labware('nest_96_wellplate_2ml_deep', '8',
                                  '96-deepwell sample plate')
    binding_buffer = ctx.load_labware(
        'opentrons_6_tuberack_falcon_50ml_conical', '11',
        '50ml tuberack for binding buffer (tube B1)').wells()[1]
    # binding_buffer = ctx.load_labware(
    #     'biorad_96_wellplate_200ul_pcr', '11',
    #     '50ml tuberack for lysis buffer + PK (tube A1)').wells()[1]
    tipracks1000 = [
        ctx.load_labware('opentrons_96_filtertiprack_1000ul', slot,
                         '1000µl filter tiprack') for slot in ['10', '7']
    ]
    tipracks20 = [
        ctx.load_labware('opentrons_96_filtertiprack_20ul', '6',
                         '20µl filter tiprack')
    ]

    # load pipette
    s20 = ctx.load_instrument('p20_single_gen2', 'left', tip_racks=tipracks20)
    p1000 = ctx.load_instrument('p1000_single_gen2',
                                'right',
                                tip_racks=tipracks1000)

    # setup samples
    sources = [well for rack in source_racks
               for well in rack.wells()][:NUM_SAMPLES]
    dests_single = dest_plate.wells()[:NUM_SAMPLES]
    num_cols = math.ceil(NUM_SAMPLES / 8)
    dests_multi = dest_plate.rows()[0][:num_cols]

    tip_log = {'count': {}}
    folder_path = '/data/A'
    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 'tips1000' in data:
                    tip_log['count'][p1000] = data['tips1000']
                else:
                    tip_log['count'][p1000] = 0
                if 'tips20' in data:
                    tip_log['count'][s20] = data['tips20']
                else:
                    tip_log['count'][s20] = 0
    else:
        tip_log['count'] = {p1000: 0, s20: 0}

    tip_log['tips'] = {
        p1000: [tip for rack in tipracks1000 for tip in rack.wells()],
        #s20: [tip for rack in tipracks20 for tip in rack.rows()[0]]
        s20: [tip for rack in tipracks20 for tip in rack.wells()]
    }
    tip_log['max'] = {pip: len(tip_log['tips'][pip]) for pip in [p1000, s20]}

    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

    heights = {binding_buffer: TUBE50_VOlUME * 1}
    radius = (binding_buffer.diameter) / 2
    min_h = 5

    def h_track(vol, tube):
        nonlocal heights
        dh = vol / (math.pi * (radius**2))
        if heights[tube] - dh > min_h:
            heights[tube] = heights[tube] - dh
        else:
            heights[tube] = min_h  # stop 5mm short of the bottom
        return heights[tube]

    p1000.flow_rate.aspirate = 50
    p1000.flow_rate.dispense = 60
    p1000.flow_rate.blow_out = 100

    # transfer internal control + proteinase K
    pick_up(s20)
    for d in dests_single:
        s20.dispense(10, ic_pk.bottom(2))
        s20.transfer(ICPK_VOlUME,
                     ic_pk.bottom(2),
                     d.bottom(2),
                     air_gap=5,
                     new_tip='never')
        s20.air_gap(5)
    s20.drop_tip()

    # # transfer binding buffer and mix
    # pick_up(p1000)
    # for i, (s, d) in enumerate(zip(sources, dests_single)):
    #
    #     source = binding_buffer[i//96]  # 1 tube of binding buffer can accommodate all samples here
    #     h = h_track(275, source)
    #     # custom mix
    #     p1000.flow_rate.aspirate = 100
    #     p1000.flow_rate.dispense = 100
    #     p1000.dispense(500, source.bottom(h+20))
    #     for _ in range(4):
    #         # p1000.air_gap(500)
    #         p1000.aspirate(500, source.bottom(h))
    #         p1000.dispense(500, source.bottom(h+20))

    pick_up(p1000)
    for i in range(math.ceil(NUM_SAMPLES / 2)):
        if NUM_SAMPLES % 2 != 0 and i == math.ceil(NUM_SAMPLES / 2) - 1:
            dest_set = [dest_plate.wells()[NUM_SAMPLES - 1]]
        else:
            dest_set = dest_plate.wells()[i * 2:i * 2 + 2]
        for i in range(len(dest_set)):
            h = h_track(BB_VOLUME, binding_buffer)
            if i == 0:
                p1000.mix(MIX_REPETITIONS, MIX_VOLUME,
                          binding_buffer.bottom(h))
            p1000.aspirate(BB_VOLUME, binding_buffer.bottom(h))
            p1000.air_gap(20)
        for s in dest_set:
            p1000.dispense(BB_VOLUME + 20, s)
    p1000.drop_tip()

    ctx.comment('Move deepwell plate (slot 4) to Station B for RNA \
extraction.')

    # track final used tip
    if not ctx.is_simulating():
        if not os.path.isdir(folder_path):
            os.mkdir(folder_path)
        data = {
            'tips1000': tip_log['count'][p1000],
            'tips20': tip_log['count'][s20]
        }
        with open(tip_file_path, 'w') as outfile:
            json.dump(data, outfile)
Example #15
0
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')
    sectempdeck = protocol.load_module('tempdeck', '10')
    fuge_rack = sectempdeck.load_labware(
        # 'opentrons_24_aluminumblock_generic_2ml_screwcap')
        'opentrons_24_aluminumblock_nest_1.5ml_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
    a_std_1 = fuge_rack['A1']  # 980ul Water + 20ul  Already prepared
    a_std_2 = fuge_rack['A2']  # 750ul water
    a_std_3 = fuge_rack['A3']  # 750ul water
    a_std_4 = fuge_rack['A4']  # 750ul water
    a_std_5 = fuge_rack['A5']  # 750ul water
    a_std_6 = fuge_rack['A6']  # 750ul water
    a_std_7 = fuge_rack['D1']  # 750ul water
    a_std_8 = fuge_rack['D2']  # 750ul water
    a_std_9 = fuge_rack['D3']  # 750ul water
    a_std_10 = fuge_rack['D4']  # 750ul water
    a_std_11 = fuge_rack['D5']  # 750ul water
    a_std_12 = fuge_rack['D6']  # 750ul water

    # LISTS
    stds = [
        a_std_1, a_std_2, a_std_3, a_std_4, a_std_5, a_std_6, a_std_7, a_std_8,
        a_std_9, a_std_10, a_std_11, a_std_12
    ]
    stds_to_add_to_PCR_tubes = [
        a_std_3, a_std_4, a_std_5, a_std_6, a_std_7, a_std_8, a_std_9, a_std_10
    ]
    num_of_sample_reps_per_holder = 6  # can't exceed 6
    holderList = [holder_1, holder_2]
    SAMP_wells = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']

    #### COMMANDS ######
    # Make std dilution series
    for i in range(len(stds) - 1):
        p300.pick_up_tip()
        p300.mix(2, 200, stds[i].bottom(4))  # mix low
        p300.mix(2, 200, stds[i].bottom(8))  # mix mid
        p300.mix(5, 200, stds[i].bottom(16))  # mix hi
        p300.aspirate(125, stds[i].bottom(8))  # 2*150 = 250
        p300.touch_tip(v_offset=-3)
        p300.dispense(125, stds[i + 1].bottom(8))
        p300.mix(2, 125, stds[i + 1].bottom(8))  # wash tip
        p300.blow_out(stds[i +
                           1].bottom(16))  # blow out just below the surface
        p300.touch_tip(v_offset=-3)
        p300.aspirate(125, stds[i].bottom(8))
        p300.touch_tip(v_offset=-3)
        p300.dispense(125, stds[i + 1].bottom(8))
        p300.mix(2, 125, stds[i + 1].bottom(8))  # wash tip
        p300.blow_out(stds[i +
                           1].bottom(16))  # blow out just below the surface
        p300.touch_tip(v_offset=-3)
        p300.drop_tip()
        if i == len(stds) - 2:  # last tube
            p300.pick_up_tip()
            p300.mix(2, 200, stds[i + 1].bottom(4))  # mix low
            p300.mix(2, 200, stds[i + 1].bottom(8))  # mix mid
            p300.mix(5, 200, stds[i + 1].bottom(16))  # mix hi
            # blow out just below the surface
            p300.blow_out(stds[i + 1].bottom(16))
            p300.drop_tip()

# Add to PCR samples
# Add sample DNA, mix, distribute to strip tubes
    for i, mixtube in enumerate(stds_to_add_to_PCR_tubes):
        for y in range(0, len(holderList)):  #usually length 1 or 2
            p300.pick_up_tip()
            p300.move_to(mixtube.bottom(40))
            p300.aspirate(num_of_sample_reps_per_holder * 20 * 1.10,
                          mixtube.bottom(2))  # 6*20*1.08 = 130
            protocol.delay(seconds=1)  #equilibrate
            p300.touch_tip(v_offset=-3)
            holderPos = y
            holder = holderList[holderPos]
            for x in range(num_of_sample_reps_per_holder):  # samples in holder
                row = SAMP_wells[i]
                dest = row + str(2 * x + 1)  # 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.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.drop_tip()
Example #16
0
def run(protocol: protocol_api.ProtocolContext):
    ################################ Variable input below ######################################################
    # Sample information
    target_con = 10  # This is the final concentration we are diluting to
    current_tip_20 = "B1"  # Where the P20 single should start on tip box.
    current_tip_300 = "B1"  # Where the p300 single should start on the tip box
    water_location = "A1"  # Location of master mix on tube_rack2
    water_loaded = False  # if you have already loaded the water for some reason this turns to True
    # Need to add a specification on what tip rack column to start on
    ############################################# Code that allows stuff to work ##########################################

    # # Creating an array for the sample plate
    alphabate = [
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
        'O', 'P'
    ]
    tube_rack_array = np.zeros((4, 6), dtype='U25')
    for col1 in range(0, 6):
        for row1 in range(0, 4):
            tube_rack_array[row1, col1] = alphabate[row1] + str(col1 + 1)

    # #  labware
    tiprack_20 = protocol.load_labware('opentrons_96_filtertiprack_20ul',
                                       tip_rack_20_loc)
    tip_rack_300 = protocol.load_labware('opentrons_96_tiprack_300ul',
                                         tip_rack_300_loc)
    tube_rack_15ml = protocol.load_labware(
        'opentrons_15_tuberack_falcon_15ml_conical', tube_rack_15ml_loc)
    tube_rack1 = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',
        tube_rack1_loc)
    tube_rack2 = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',
        tube_rack2_loc)
    tube_rack3 = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',
        tube_rack3_loc)
    tube_rack4 = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',
        tube_rack4_loc)
    tube_rack5 = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',
        tube_rack5_loc)
    tube_rack6 = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',
        tube_rack6_loc)
    tube_rack7 = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',
        tube_rack7_loc)
    tube_rack8 = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',
        tube_rack8_loc)

    # #  pipettes
    left_pipette = protocol.load_instrument('p20_single_gen2',
                                            'left',
                                            tip_racks=[tiprack_20])
    right_pipette = protocol.load_instrument('p300_single_gen2',
                                             'right',
                                             tip_racks=[tip_rack_300])

    # #  Set starting tip
    left_pipette.starting_tip = tiprack_20.wells_by_name()[current_tip_20]
    right_pipette.starting_tip = tip_rack_300.wells_by_name()[current_tip_300]

    # #  setting water location
    water_well = tube_rack_15ml.wells_by_name()[water_location]

    # # formatting data better
    aspirations = set_up_data(concentrations, target_con)

    # commands

    # Loading water
    if not water_loaded:
        right_pipette.pick_up_tip()
        for i in range(0, len(aspirations)):
            water_drop = get_tube_positions(i, tube_rack_array)
            if (i > 71) & (i <= 95):
                right_pipette.transfer(aspirations[2][i],
                                       water_well,
                                       tube_rack8.wells_by_name()[water_drop],
                                       new_tip='never',
                                       air_gap=5)
            if (i > 47) & (i <= 71):
                right_pipette.transfer(aspirations[2][i],
                                       water_well,
                                       tube_rack6.wells_by_name()[water_drop],
                                       new_tip='never',
                                       air_gap=5)
            if (i > 23) & (i <= 47):
                right_pipette.transfer(aspirations[2][i],
                                       water_well,
                                       tube_rack4.wells_by_name()[water_drop],
                                       new_tip='never',
                                       air_gap=5)
            if (i >= 0) & (i <= 23):
                right_pipette.transfer(aspirations[2][i],
                                       water_well,
                                       tube_rack2.wells_by_name()[water_drop],
                                       new_tip='never',
                                       air_gap=5)
        right_pipette.drop_tip()

    # adding sample to water
    for i in range(0, len(aspirations)):
        tube_position = get_tube_positions(i, tube_rack_array)
        if (i > 71) & (i <= 95):
            left_pipette.transfer(aspirations[1][i],
                                  tube_rack7.wells_by_name()[tube_position],
                                  tube_rack8.wells_by_name()[tube_position],
                                  air_gap=3,
                                  rate=2.0)
        if (i > 47) & (i <= 71):
            left_pipette.transfer(aspirations[1][i],
                                  tube_rack5.wells_by_name()[tube_position],
                                  tube_rack6.wells_by_name()[tube_position],
                                  air_gap=3,
                                  rate=2.0)
        if (i > 23) & (i <= 47):
            left_pipette.transfer(aspirations[1][i],
                                  tube_rack3.wells_by_name()[tube_position],
                                  tube_rack4.wells_by_name()[tube_position],
                                  air_gap=3,
                                  rate=2.0)
        if (i >= 0) & (i <= 23):
            left_pipette.transfer(aspirations[1][i],
                                  tube_rack1.wells_by_name()[tube_position],
                                  tube_rack2.wells_by_name()[tube_position],
                                  air_gap=3,
                                  rate=2.0)
Example #17
0
def run(protocol: protocol_api.ProtocolContext):
    """
    Pick up p20 and/or p300 tips, followed by touch bottom of tubes 
    of different labware
    """
    # =============================================================================

    # LOADING LABWARE==============================================================
    # =============================================================================
    labwares = []
    ## empty list to add labware to, to loop through

    ##### Loading pipettetips
    if pipette300:
        tips_200 = protocol.load_labware('opentrons_96_filtertiprack_200ul',
                                         10, '200tips')
    if pipette20:
        tips_20 = protocol.load_labware('opentrons_96_filtertiprack_20ul', 11,
                                        '20tips')

    ##### Loading labware
    if plate:
        plate_96 = protocol.load_labware('biorad_96_wellplate_200ul_pcr', 1,
                                         '96well_plate')
        labwares.append(plate_96)
    if plate_on_rack:
        plate_coolrack = protocol.load_labware(
            'biorad_qpcr_plate_eppendorf_cool_rack', 2, '96well_plate_on_rack')
        labwares.append(plate_coolrack)
    if strips:
        pcr_strips = protocol.load_labware('pcrstrips_96_wellplate_200ul', 3,
                                           'pcr_strips')
        labwares.append(pcr_strips)
    if tubes:
        sample_tubes = protocol.load_labware(
            'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap', 4,
            'sample_tubes')
        labwares.append(sample_tubes)

    if tubes5mL:
        tubes_5mL = protocol.load_labware(
            'eppendorfscrewcap_15_tuberack_5000ul', 5, 'tubes_5mL')
        labwares.append(tubes_5mL)

    ##### Loading pipettes
    if pipette300:
        p300 = protocol.load_instrument('p300_single_gen2',
                                        'right',
                                        tip_racks=[tips_200])
    if pipette20:
        p20 = protocol.load_instrument('p20_single_gen2',
                                       'left',
                                       tip_racks=[tips_20])
# =============================================================================

# START-UP=====================================================================
# =============================================================================
    protocol.set_rail_lights(True)
    ## turn on lights

    if pipette300:
        p300.starting_tip = tips_200.well(p300_start_tip)
        ## define first tip
        p300.pick_up_tip()
        ## pick up first tip
    if pipette20:
        p20.starting_tip = tips_20.well(p20_start_tip)
        ## define first tip
        p20.pick_up_tip()
        ## pick up first tip
# =============================================================================

# test labwares
# =============================================================================
    for labware in labwares:
        # wells
        wells = []
        if test_wells:
            all_wells = labware.wells()
            total_number_of_wells = len(all_wells)
            middle = int(total_number_of_wells / 2)
            wells.append(all_wells[0])
            wells.append(all_wells[middle])
            wells.append(all_wells[-1])
            ## pick 3 wells, nicely distributed of the labware
        if test_columns:
            all_columns = labware.columns()
            total_number_of_columns = len(all_columns)
            middle = int(total_number_of_columns / 2)
            columns = []
            columns.append(all_columns[0])
            columns.append(all_columns[middle])
            columns.append(all_columns[-1])
            ## pick 3 columns, nicely distributed of the labware
            for column in columns:
                for well in column:
                    wells.append(well)

            for well in wells:
                if pipette300:
                    p300.move_to(well.bottom())
                    protocol.delay(seconds=1)
            for well in wells:
                if pipette20:
                    p20.move_to(well.bottom())
                    protocol.delay(seconds=1)
# =============================================================================

# SHUT DOWN====================================================================
# =============================================================================
    if pipette300:
        p300.return_tip()
    if pipette20:
        p20.return_tip()
    protocol.set_rail_lights(False)


# =============================================================================
def run(ctx: protocol_api.ProtocolContext):
    ctx.comment('Actual used columns: ' + str(num_cols))
    # Define the STEPS of the protocol
    STEP = 0
    STEPS = {  # Dictionary with STEP activation, description, and times

        1: {'Execute': True, 'description': 'Add 300 ul Wash Buffer 1 - Round 1'},
        2: {'Execute': True, 'description': 'Add 300 ul Wash Buffer 1 - Round 2'},
        3: {'Execute': True, 'description': 'Add 450 ul Wash Buffer 2 - Round 1'},
        4: {'Execute': True, 'description': 'Add 450 ul Wash Buffer 2 - Round 2'},
        5: {'Execute': True, 'description': 'Add 50 ul Elution Buffer'},
    }

    for s in STEPS:  # Create an empty wait_time
        if 'wait_time' not in STEPS[s]:
            STEPS[s]['wait_time'] = 0
    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 + '/KB_PlateFilling_pathogen_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, h_cono, v_fondo,
                      tip_recycling = 'none'):
            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 #Delay of reagent in dispense
            self.num_wells = num_wells
            self.col = 0
            self.vol_well = 0
            self.h_cono = h_cono
            self.v_cono = v_fondo
            self.unused=[]
            self.tip_recycling = tip_recycling
            self.vol_well_original = reagent_reservoir_volume / num_wells

    # Reagents and their characteristics
    WashBuffer1 = Reagent(name='Wash Buffer 1',
                          flow_rate_aspirate=0.75,
                          flow_rate_dispense=1,
                          rinse=True,
                          delay=2,
                          reagent_reservoir_volume=100000,
                          num_wells=1,
                          h_cono=0,
                          v_fondo=0)  # Flat surface

    WashBuffer2 = Reagent(name='Wash Buffer 1',
                          flow_rate_aspirate=0.75,
                          flow_rate_dispense=1,
                          rinse=True,
                          delay=2,
                          reagent_reservoir_volume=100000,
                          num_wells=1,
                          h_cono=0,
                          v_fondo=0)  # Flat surface

    ElutionBuffer = Reagent(name='Elution Buffer',
                            flow_rate_aspirate=1,
                            flow_rate_dispense=1,
                            rinse=False,
                            delay=0,
                            reagent_reservoir_volume=50*NUM_SAMPLES,
                            num_wells=1,
                            h_cono=1.95,
                            v_fondo=695)  # Prismatic

    WashBuffer1.vol_well = WashBuffer1.vol_well_original
    WashBuffer2.vol_well = WashBuffer2.vol_well_original
    ElutionBuffer.vol_well = ElutionBuffer.vol_well_original

    ##################
    # Custom functions
    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, rate = reagent.flow_rate_aspirate)  # 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(radius=0.9, speed = 20, v_offset = -5) #radius here is 0.9


    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

    def calc_height(reagent, cross_section_area, aspirate_volume, min_height = 0.5):
        nonlocal ctx
        ctx.comment('Remaining volume ' + str(reagent.vol_well) +
                    '< needed volume ' + str(aspirate_volume) + '?')
        if reagent.vol_well < aspirate_volume:
            reagent.unused.append(reagent.vol_well)
            ctx.comment('Next column should be picked')
            ctx.comment('Previous to change: ' + str(reagent.col))
            # column selector position; intialize to required number
            reagent.col = reagent.col + 1
            ctx.comment(str('After change: ' + str(reagent.col)))
            reagent.vol_well = reagent.vol_well_original
            ctx.comment('New volume:' + str(reagent.vol_well))
            height = (reagent.vol_well - aspirate_volume - reagent.v_cono) / cross_section_area
                    #- reagent.h_cono
            reagent.vol_well = reagent.vol_well - aspirate_volume
            ctx.comment('Remaining volume:' + str(reagent.vol_well))
            if height < min_height:
                height = min_height
            col_change = True
        else:
            height = (reagent.vol_well - aspirate_volume - reagent.v_cono) / cross_section_area #- reagent.h_cono
            reagent.vol_well = reagent.vol_well - aspirate_volume
            ctx.comment('Calculated height is ' + str(height))
            if height < min_height:
                height = min_height
            ctx.comment('Used height is ' + str(height))
            col_change = False
        return height, col_change

    ##########
    # 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
        pip.pick_up_tip()
    ##########

    def find_side(col):
        '''
        Detects if the current column has the magnet at its left or right side
        '''
        if col % 2 == 0:
            side = -1  # left
        else:
            side = 1
        return side


####################################
    # load labware and modules

    # 12 well rack
    ####################################
    reagent_res = ctx.load_labware(
        'nest_12_reservoir_15ml', '3', 'Reservoir 12 channel, column 1')

    # WashBuffer1 reservoir
    ####################################
    WashBuffer1_reservoir = ctx.load_labware(
        'nalgene_1_reservoir_300000ul', '2', 'Ethanol 80% reservoir')

    # WashBuffer2 reservoir
    ####################################
    WashBuffer2_reservoir = ctx.load_labware(
        'nalgene_1_reservoir_300000ul', '11', 'WashBuffer reservoir')

    # Wash Buffer 1 300ul Deepwell plate
    ############################################
    WashBuffer1_300ul_plate1 = ctx.load_labware(
        'kf_96_wellplate_2400ul', '1', 'Wash Buffer 1 Deepwell plate 1')

    # Wash Buffer 1 300ul Deepwell plate
    ############################################
    WashBuffer1_300ul_plate2 = ctx.load_labware(
        'kf_96_wellplate_2400ul', '4', 'Wash Buffer 1 Deepwell plate 2')

    # Wash Buffer 2 450ul Deepwell plate
    ############################################
    WashBuffer2_450ul_plate1 = ctx.load_labware(
        'kf_96_wellplate_2400ul', '7', 'Wash Buffer 2 Deepwell plate 1')

    # Wash Buffer 2 450ul Deepwell plate
    ############################################
    WashBuffer2_450ul_plate2 = ctx.load_labware(
        'kf_96_wellplate_2400ul', '10', 'Wash Buffer 2 Deepwell plate 2')

    # Elution Deepwell plate
    ############################################
    ElutionBuffer_50ul_plate = ctx.load_labware(
        'kingfisher_std_96_wellplate_550ul', '6', 'Elution Buffer 50 ul STD plate')


####################################
    # Load tip_racks
    tips300 = [ctx.load_labware('opentrons_96_tiprack_300ul', slot, '200µl filter tiprack')
               for slot in ['8']]

################################################################################
    # Declare which reagents are in each reservoir as well as deepwell and elution plate
    WashBuffer1.reagent_reservoir = WashBuffer1_reservoir.wells()[0]
    WashBuffer2.reagent_reservoir = WashBuffer2_reservoir.wells()[0]
    ElutionBuffer.reagent_reservoir = reagent_res.rows()[0][0]

    # columns in destination plates to be filled depending the number of samples
    wb1plate1_destination = WashBuffer1_300ul_plate1.rows()[0][:num_cols]
    wb1plate2_destination = WashBuffer1_300ul_plate2.rows()[0][:num_cols]
    wb2plate1_destination = WashBuffer2_450ul_plate1.rows()[0][:num_cols]
    wb2plate2_destination = WashBuffer2_450ul_plate2.rows()[0][:num_cols]
    elutionbuffer_destination = ElutionBuffer_50ul_plate.rows()[0][:num_cols]

    # pipette
    m300 = ctx.load_instrument(
        'p300_multi_gen2', 'right', tip_racks=tips300)  # Load multi pipette

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

    ############################################################################
    # STEP 1 Filling with WashBuffer1 plate 1
    ############################################################################
    STEP += 1
    if STEPS[STEP]['Execute'] == True:
        start = datetime.now()

        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'])
        ctx.comment('###############################################')

        wash_buffer_vol = [150, 150]
        rinse = False  # Only first time

        ########
        # Wash buffer dispense
        for i in range(num_cols):
            if not m300.hw_pipette['has_tip']:
                pick_up(m300)
            for j, transfer_vol in enumerate(wash_buffer_vol):
                if (i == 0 and j == 0):
                    rinse = True #Rinse only first transfer
                else:
                    rinse = False
                move_vol_multichannel(m300, reagent = WashBuffer1, source = WashBuffer1.reagent_reservoir,
                               dest = wb1plate1_destination[i], vol = transfer_vol,
                               air_gap_vol = air_gap_vol, x_offset = x_offset,
                               pickup_height = 1, rinse = rinse, disp_height = -2,
                               blow_out = True, touch_tip = True)
        m300.drop_tip(home_after=True)
        tip_track['counts'][m300] += 8
        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 Filling with WashBuffer1 plate 2
    ############################################################################
    STEP += 1
    if STEPS[STEP]['Execute'] == True:
        start = datetime.now()

        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'])
        ctx.comment('###############################################')

        wash_buffer_vol = [150, 150]
        rinse = False  # Only first time

        ########
        # Wash buffer dispense
        for i in range(num_cols):
            if not m300.hw_pipette['has_tip']:
                pick_up(m300)
            for j, transfer_vol in enumerate(wash_buffer_vol):
                if (i == 0 and j == 0):
                    rinse = True
                else:
                    rinse = False
                move_vol_multichannel(m300, reagent = WashBuffer1, source = WashBuffer1.reagent_reservoir,
                               dest = wb1plate2_destination[i], vol = transfer_vol,
                               air_gap_vol = air_gap_vol, x_offset = x_offset,
                               pickup_height = 1, rinse = rinse, disp_height = -2,
                               blow_out = True, touch_tip = True)
        m300.drop_tip(home_after=True)
        tip_track['counts'][m300] += 8
        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 3 Filling with WashBuffer2 plate 1
    ############################################################################
    STEP += 1
    if STEPS[STEP]['Execute'] == True:
        start = datetime.now()

        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'])
        ctx.comment('###############################################')

        wash_buffer_vol = [150, 150, 150]
        rinse = False  # Only first time

        ########
        # Wash buffer dispense
        for i in range(num_cols):
            if not m300.hw_pipette['has_tip']:
                pick_up(m300)
            for j, transfer_vol in enumerate(wash_buffer_vol):
                if (i == 0 and j == 0):
                    rinse = True
                else:
                    rinse = False
                move_vol_multichannel(m300, reagent = WashBuffer2, source = WashBuffer2.reagent_reservoir,
                               dest = wb2plate1_destination[i], vol = transfer_vol,
                               air_gap_vol = air_gap_vol, x_offset = x_offset,
                               pickup_height = 1, rinse = rinse, disp_height = -2,
                               blow_out = True, touch_tip = True)
        m300.drop_tip(home_after=True)
        tip_track['counts'][m300] += 8
        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 Filling with WashBuffer2 plate 2
    ############################################################################
    STEP += 1
    if STEPS[STEP]['Execute'] == True:
        start = datetime.now()

        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'])
        ctx.comment('###############################################')

        ethanol_vol = [150, 150, 150]
        rinse = False  # Only first time

        ########
        # Ethanol dispense
        for i in range(num_cols):
            if not m300.hw_pipette['has_tip']:
                pick_up(m300)
            for j, transfer_vol in enumerate(ethanol_vol):
                if (i == 0 and j == 0):
                    rinse = True
                else:
                    rinse = False
                move_vol_multichannel(m300, reagent = WashBuffer2, source = WashBuffer2.reagent_reservoir,
                              dest = wb2plate2_destination[i], vol = transfer_vol,
                              air_gap_vol = air_gap_vol, x_offset = x_offset,
                              pickup_height = 1, rinse = rinse, disp_height = -2,
                              blow_out = True, touch_tip = True)
        m300.drop_tip(home_after=True)
        tip_track['counts'][m300] += 8
        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 Elution buffer
    ############################################################################

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

        ########
        # Water or elution buffer
        for i in range(num_cols):
            if not m300.hw_pipette['has_tip']:
                pick_up(m300)
            for transfer_vol in ElutionBuffer_vol:
                # Calculate pickup_height based on remaining volume and shape of container
                [pickup_height, change_col] = calc_height(
                    ElutionBuffer, multi_well_rack_area, transfer_vol * 8)
                ctx.comment(
                    'Aspirate from Reservoir column: ' + str(ElutionBuffer.col))
                ctx.comment('Pickup height is ' + str(pickup_height))
                move_vol_multichannel(m300, reagent = ElutionBuffer, source = ElutionBuffer.reagent_reservoir,
                              dest = elutionbuffer_destination[i], vol = transfer_vol,
                              air_gap_vol = air_gap_vol_elutionbuffer, x_offset = x_offset,
                              pickup_height = pickup_height, rinse = False, disp_height = -2,
                              blow_out = True, touch_tip = False)
        m300.drop_tip(home_after=True)
        tip_track['counts'][m300] += 8
        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
    from opentrons.drivers.rpi_drivers import gpio
    for i in range(3):
        gpio.set_rail_lights(False)
        gpio.set_button_light(1, 0, 0)
        time.sleep(0.3)
        gpio.set_rail_lights(True)
        gpio.set_button_light(0, 0, 1)
        time.sleep(0.3)
    gpio.set_button_light(0, 1, 0)
    ctx.comment(
        'Finished! \nMove deepwell plates to KingFisher extractor.')
    ctx.comment('Used tips in total: ' + str(tip_track['counts'][m300]))
    ctx.comment('Used racks in total: ' + str(tip_track['counts'][m300] / 96))
def run(ctx: protocol_api.ProtocolContext):
    STEP = 0
    STEPS = {  # Dictionary with STEP activation, description and times
        1: {
            'Execute':
            False,
            'description':
            'Dispensar Proteinasa K (' + str(PK_VOL_PER_SAMPLE) + 'ul)'
        },
        2: {
            'Execute':
            True,
            'description':
            'Mezclar y dispensar muestras (' + str(VOLUME_SAMPLE) + 'ul)'
        }
    }
    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
    if not ctx.is_simulating():
        folder_path = '/var/lib/jupyter/notebooks/' + run_id
        if not os.path.isdir(folder_path):
            os.mkdir(folder_path)
        file_path = folder_path + '/StationA_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
    Samples = Reagent(
        name='Samples',
        flow_rate_aspirate=25,
        flow_rate_dispense=100,
        rinse=False,
        delay=0,
        reagent_reservoir_volume=0,
        num_wells=96,
    )

    Pk = Reagent(name='Pk',
                 rinse=False,
                 flow_rate_aspirate=3,
                 flow_rate_dispense=3,
                 reagent_reservoir_volume=1800,
                 num_wells=1,
                 delay=0)

    ctx.comment(' ')
    ctx.comment('###############################################')
    ctx.comment('CONTROLES: ' + str(NUM_CONTROL_SPACES))
    ctx.comment('MUESTRAS: ' + str(NUM_REAL_SAMPLES))
    ctx.comment('###############################################')
    ctx.comment(' ')

    ##################
    # 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,
                          touch_tip=False,
                          num_shakes=0):
        pipette.aspirate((len(dest) * volume) + extra_dispensal,
                         src.bottom(pickup_height))
        if touch_tip:
            pipette.touch_tip(speed=20, v_offset=-5)

        for d in dest:
            drop = d.top(z=disp_height)
            pipette.dispense(volume, drop)

            shake_pipet(pipette, rounds=num_shakes, v_offset=disp_height)
        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,
                              shakes=0,
                              shake_v_offset=-45):
        '''
        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,
                       rate=reagent.flow_rate_aspirate)  # aspirate liquid

        if shakes > 0:
            shake_pipet(pipet, v_offset=shake_v_offset)

        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=disp_height))

        if touch_tip == True:
            pipet.touch_tip(speed=20, v_offset=-10)

        if air_gap_vol != 0:
            pipet.air_gap(air_gap_vol, height=disp_height)  #air gap

    def custom_mix(pipet,
                   reagent,
                   location,
                   vol,
                   rounds,
                   blow_out,
                   mix_height,
                   x_offset,
                   source_height=5):
        '''
        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

    def generate_source_table(source):
        '''
        Concatenate the wells frome the different origin racks
        '''
        num_cols = math.ceil(num_samples / 8)
        s = []
        for i in range(num_cols):
            if i < 6:
                s += source[0].columns()[i] + source[1].columns()[i]
            else:
                s += source[2].columns()[i - 6] + source[3].columns()[i - 6]
        return s

    def shake_pipet(pipet, rounds=2, speed=100, v_offset=0):
        ctx.comment("Shaking " + str(rounds) + " rounds.")
        for i in range(rounds):
            pipet.touch_tip(speed=speed, radius=0.1, v_offset=v_offset)

    ##########
    # 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
        pip.pick_up_tip()

    def run_quiet_process(command):
        subprocess.check_output('{} &> /dev/null'.format(command), shell=True)

    def play_sound(filename):
        print('Speaker')
        print('Next\t--> CTRL-C')
        try:
            run_quiet_process('mpg123 {}'.format(path_sounds + filename +
                                                 '.mp3'))
            run_quiet_process('mpg123 {}'.format(path_sounds + sonido_defecto))
            run_quiet_process('mpg123 {}'.format(path_sounds + filename +
                                                 '.mp3'))

        except KeyboardInterrupt:
            pass
            print()

    def start_run():
        ctx.comment(' ')
        ctx.comment('###############################################')
        ctx.comment('Empezando protocolo')
        if PHOTOSENSITIVE == False:
            ctx._hw_manager.hardware.set_lights(button=True, rails=True)
        else:
            ctx._hw_manager.hardware.set_lights(button=True, rails=False)
        now = datetime.now()

        # dd/mm/YY H:M:S
        start_time = now.strftime("%Y/%m/%d %H:%M:%S")
        return start_time

    def finish_run(switch_off_lights=False):
        ctx.comment('###############################################')
        ctx.comment('Protocolo finalizado')
        ctx.comment(' ')
        #Set light color to blue
        ctx._hw_manager.hardware.set_lights(button=True, rails=False)
        now = datetime.now()
        # dd/mm/YY H:M:S
        finish_time = now.strftime("%Y/%m/%d %H:%M:%S")
        if PHOTOSENSITIVE == False:
            for i in range(10):
                ctx._hw_manager.hardware.set_lights(button=False, rails=False)
                time.sleep(0.3)
                ctx._hw_manager.hardware.set_lights(button=True, rails=True)
                time.sleep(0.3)
        else:
            for i in range(10):
                ctx._hw_manager.hardware.set_lights(button=False, rails=False)
                time.sleep(0.3)
                ctx._hw_manager.hardware.set_lights(button=True, rails=False)
                time.sleep(0.3)
        if switch_off_lights:
            ctx._hw_manager.hardware.set_lights(button=True, rails=False)

        used_tips = tip_track['num_refills'][p1000] * 96 * len(
            p1000.tip_racks) + tip_track['counts'][p1000]
        ctx.comment('Puntas de 1000 ul utilizadas: ' + str(used_tips) + ' (' +
                    str(round(used_tips / 96, 2)) + ' caja(s))')
        ctx.comment('###############################################')

        if not ctx.is_simulating():
            for i in range(SOUND_NUM_PLAYS):
                if i > 0:
                    time.sleep(60)
                play_sound('finished_process_esp')

            return finish_time

    ####################################
    # load labware and modules

    ####################################
    # Load Sample racks
    if num_samples <= 48:
        rack_num = 2
        ctx.comment('Used source racks are ' + str(rack_num))
    else:
        rack_num = 4

    #source_racks = [ctx.load_labware(
    #    'pcr_24_wellplate_13200ul', slot,
    #    'source tuberack with snapcap' + str(i + 1)) for i, slot in enumerate(['4', '1', '5', '2'][:rack_num])
    #]

    source_racks = [
        ctx.load_labware('vitrobiocomma_24_tuberack_15000ul_1', '4',
                         'samples grid 1'),
        ctx.load_labware('vitrobiocomma_24_tuberack_15000ul_2', '1',
                         'samples grid 2'),
        ctx.load_labware('vitrobiocomma_24_tuberack_15000ul_3', '5',
                         'samples grid 3'),
        ctx.load_labware('vitrobiocomma_24_tuberack_15000ul_4', '2',
                         'samples grid 4')
    ]

    ##################################
    # Destination plate
    dest_plate = ctx.load_labware('nest_96_wellplate_2ml_deep', '6',
                                  'NEST 96 Deepwell Plate 2mL')

    pk_rack = ctx.load_labware('opentrons_24_tuberack_nest_1.5ml_screwcap',
                               '3',
                               'opentrons_24_tuberack_nest_1.5ml_screwcap')
    ####################################
    # Load tip_racks
    tips1000 = [
        ctx.load_labware(
            'opentrons_96_filtertiprack_1000ul' if OPENTRONS_TIPS else
            'geb_96_tiprack_1000ul', slot, '1000µl filter tiprack')
        for slot in ['8']
    ]
    tips300 = [
        ctx.load_labware('opentrons_96_tiprack_300ul', slot) for slot in ['7']
    ]

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

    ################################################################################
    # setup samples and destinations
    sample_sources_full = generate_source_table(source_racks)
    sample_sources = sample_sources_full[NUM_CONTROL_SPACES:num_samples]
    destinations = dest_plate.wells()[NUM_CONTROL_SPACES:num_samples]

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

    p1000 = ctx.load_instrument('p1000_single_gen2',
                                'left',
                                tip_racks=tips1000)  # load P1000 pipette
    p300 = ctx.load_instrument('p300_single_gen2',
                               mount='right',
                               tip_racks=tips300)

    # used tip counter and set maximum tips available
    tip_track = {
        'counts': {
            p1000: 0,
            p300: 0
        },
        'maxes': {
            p1000: 96 * len(p1000.tip_racks),
            p300: 96 * len(p300.tip_racks)
        },  #96 tips per tiprack * number or tipracks in the layout
        'num_refills': {
            p1000: 0,
            p300: 0
        },
        'tips': {
            p1000: [tip for rack in tips1000 for tip in rack.rows()[0]],
            p300: [tip for rack in tips300 for tip in rack.rows()[0]]
        }
    }

    start_run()

    ############################################################################
    # STEP 1: DISPENSAR PK
    ############################################################################
    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:
            ctx.comment(
                'dest length ---------------------------------------------- ' +
                str(len(dest)))
            aspirate_volume = PK_VOL_PER_SAMPLE * len(dest) + extra_dispensal
            used_vol_temp = distribute_custom(p300,
                                              volume=PK_VOL_PER_SAMPLE,
                                              src=Pk.reagent_reservoir,
                                              dest=dest,
                                              touch_tip=False,
                                              waste_pool=Pk.reagent_reservoir,
                                              pickup_height=0.2,
                                              extra_dispensal=extra_dispensal,
                                              dest_x_offset=0,
                                              disp_height=-15,
                                              num_shakes=PK_SAKES)
            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: MIX AND MOVE SAMPLES
    ############################################################################
    STEP += 1
    if STEPS[STEP]['Execute'] == True:
        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'])
        ctx.comment('###############################################')

        start = datetime.now()
        for s, d in zip(sample_sources, destinations):
            if not p1000.hw_pipette['has_tip']:
                pick_up(p1000)

            # Mix the sample BEFORE dispensing
            if NUM_MIXES > 0:
                custom_mix(p1000,
                           reagent=Samples,
                           location=s,
                           vol=volume_mix,
                           rounds=NUM_MIXES,
                           blow_out=True,
                           mix_height=5,
                           x_offset=x_offset)

            move_vol_multichannel(p1000,
                                  reagent=Samples,
                                  source=s,
                                  dest=d,
                                  vol=VOLUME_SAMPLE,
                                  air_gap_vol=air_gap_vol_sample,
                                  x_offset=x_offset,
                                  pickup_height=5,
                                  rinse=Samples.rinse,
                                  disp_height=-10,
                                  blow_out=True,
                                  touch_tip=False,
                                  shakes=SAMPLE_SAKES)

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

        # Time statistics
        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
    # from opentrons.drivers.rpi_drivers import gpio

    finish_run(switch_off_lights)
Example #20
0
def run(protocol: protocol_api.ProtocolContext):
    """Function to transfer 100ul from 1 well to another."""

#loading labware (from opentrons labware library)
    plate = protocol.load_labware('biorad_96_wellplate_200ul_pcr', 1, 
        '96plate')
    tiprack_1 = protocol.load_labware('opentrons_96_tiprack_300ul', 2, 
        '300tips')
#load pipette 
    p300 = protocol.load_instrument('p300_single_gen2', 'right', 
        tip_racks=[tiprack_1])
    
#run protocol
    while protocol.door_closed:
        if not protocol.door_closed:
            protocol.set_rail_lights(True)
            protocol.home()
            protocol.pause('Press resume when you are ready :)!')        
    
        protocol.set_rail_lights(False)        
     
    #transfer 100ul from plate well A1 to plate well B1 with default settings    
        p300.pick_up_tip()
         #aspirate & dispense at default flow rate of 92.86 ul/s
        p300.aspirate(100, plate['A1'])
        p300.dispense(100, plate['B1'])
        p300.blow_out() #blow out in current location
        p300.drop_tip() #automatically in trash
        
    #all following pipetting steps with changed default flow rates
         #aspirate at 150 ul/s
        p300.flow_rate.aspirate = 150
         #dispense at 300 ul/s
        p300.flow_rate.dispense = 300
         #blow out at 200 ul/s
        p300.flow_rate.blow_out = 200  
        
        p300.pick_up_tip()
        p300.aspirate(100, plate['C1'])
        p300.dispense(100, plate['D1'])
        p300.blow_out(plate['D1']) #blow out in destination well
        p300.drop_tip() #automatically in trash
    
        
    #all following pipetting steps aspirate & dispense other height (in mm)
         #aspirate 2 mm from bottom
        p300.well_bottom_clearance.aspirate = 3
         #dispense 10 mm from bottom
        p300.well_bottom_clearance.dispense = 10 
        
        p300.pick_up_tip()
        p300.aspirate(100, plate['E1'])
        p300.dispense(100, plate['F1'])
        p300.blow_out(plate['F1']) #blow out in destination well
        p300.drop_tip() #automatically in trash
        
        #display a comment in the opentrons app
        protocol.comment('Hello you!')
    
    #all following pipetting steps with per-axis speed limits
         #limit x-axis to 50 mm/s
        protocol.max_speeds['X'] = 50
         #limit y-axis to 50 mm/s
        protocol.max_speeds['Y'] = 50
         #limit a-axis to 50 mm/s
        protocol.max_speeds['A'] = 50
        
        p300.pick_up_tip()
        p300.aspirate(100, plate['G1'])
        p300.dispense(100, plate['H1'])
        p300.blow_out(plate['H1']) #blow out in destination well
        p300.drop_tip() #automatically in trash
        
    #all following pipetting steps with per-axis speed limits to default
         #reset x-axis speed limit - delete method
        del protocol.max_speeds['X']
         #reset y-axis speed limit - none method
        protocol.max_speeds['Y'] = None
         #reset a-axis speed limit - none method
        protocol.max_speeds['A'] = None
        
        p300.pick_up_tip()
        p300.aspirate(100, plate['B1'])
        p300.dispense(100, plate['A1'])
        p300.blow_out(plate['A1']) #blow out in destination well
        p300.drop_tip() #automatically in trash
        
        break
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

    #fuge_rack
    MIX_master = fuge_rack['D1']  # see sheet, but ~2075
    WATER = fuge_rack['A1']  # 1500ul WATER

    samp_1 = fuge_rack['B1']  # e.g. 0.625uM # empty
    samp_2 = fuge_rack['B2']  # e.g. 1.25uM # empty
    samp_3 = fuge_rack['B3']  # e.g. 2.5uM # empty
    samp_4 = fuge_rack['B4']  # e.g. 5.0uM # empty
    samp_5 = fuge_rack['B5']  # e.g. 7.5uM # empty
    samp_6 = fuge_rack['B6']  # e.g. 10uM # empty

    # user inputs
    p300_max_vol = 200
    mix_master_tot = 96 * 18 * 1.2  # total vol of mastermix
    mmix_XFR_std_mix = 3 * 18 * 1.14  # transfer this amount to the std mix intermediate tubes that will receive DNA
    std_dna_XFR_to_std_int = 3 * 2 * 1.14  #transfer this amount DNA to std_int_tubes to mix and aliquot to 3 wells
    mmix_XFR_samp_wells = 18 * 12 * 1.1  # how much mastermix transferred as bolus to well A1, B1..F1 to receive DNA

    # lists
    # all_std_tubes = [std_1, std_2, std_3, std_4, std_5, std_6, std_7, std_8, std_9, std_10, std_11, std_12, std_13, std_14, std_15, std_16]
    # all_std_tubes = [std_1, std_2, std_3, std_4, std_5, std_6, std_7, std_8]
    # std_tubes = [std_2, std_3, std_4, std_5, std_6, std_7, std_8, WATER]
    # 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_wells = ['A1', 'B1', 'C1', 'D1', 'E1', 'F1']
    # samp_sources = [std_1, std_2, std_3, std_4, std_5, std_6]
    # samp_sources = [std_12, std_13, std_14, std_15, std_16, std_17]
    samp_sources = [samp_1, samp_2, samp_3, samp_4, samp_5, samp_6]

    # ### COMMANDS ######
    # # make pos control standards
    # # transfer from pos_control to make std_1
    # pos_control_height = tip_heights(400,1,10)
    # p20.transfer(
    #     10,
    #     pos_control.bottom(pos_control_height[0]), #1uM
    #     std_1.bottom(20),
    #     mix_after=(2, 20), # remove residual fluid from tip
    #     touch_tip=True
    # )

    # # serial dilutions in microfuge tubes, 10% diliutions
    # p300.pick_up_tip()
    # for i in range(len(all_std_tubes)-1): #don't want out of range because i + 1
    #     last_std_tube = len(all_std_tubes)-1 # (int) position of last std tube; last tube = WATER
    #     h_mix = 20
    #     if i==0 or i==last_std_tube: # first or last std tube; not WATER
    #         p300.mix(3, 200, all_std_tubes[i].bottom(h_mix)) # need to add mixes to first and last tubes
    #     p300.mix(5, 200, all_std_tubes[i].bottom(h_mix))
    #     p300.flow_rate.aspirate = 40 #slow aspirate; no air
    #     p300.aspirate(100,all_std_tubes[i].bottom(h_mix))
    #     p300.touch_tip()
    #     p300.flow_rate.dispense = 40 #slow dispense
    #     p300.dispense(100, all_std_tubes[i+1])
    #     p300.flow_rate.aspirate = 92.86 #default
    #     p300.flow_rate.dispense = 92.86 #default
    #     p300.mix(3, 200,all_std_tubes[i+1].bottom(h_mix)) #remove residual inside tip
    #     # p300.move_to(std_wells[i+1].bottom(15)) #come up for blowout
    #     p300.blow_out()
    #     protocol.delay(seconds=2) #wait for bubbles to subside
    # p300.drop_tip()

    # # Mastermix contains primers and probe. Everything except DNA. Aliquot to 6 tubes.
    # # transfer sN_mix to intermediate tubes (std_mixes)
    # p300.pick_up_tip()
    # p300.flow_rate.aspirate = 92.86 #default
    # p300.flow_rate.dispense = 92.86 #default
    # mmix_h = tip_heightsEpp(mix_master_tot, len(std_mixes), mmix_XFR_std_mix)
    # # print ("mix_master_tot", mix_master_tot)
    # # print (len(std_mixes))
    # # print (mmix_XFR_std_mix)
    # # print ("mmix_h", mmix_h)
    # p300.mix(6, 200, MIX_master.bottom(mmix_h[0])) # top tip height
    # p300.flow_rate.aspirate = 30
    # p300.flow_rate.dispense = 40
    # # p300.well_bottom_clearance.aspirate = std_mix_heights[0] #mm
    # for i, tube in enumerate(std_mixes):
    #     # p300.well_bottom_clearance.aspirate = h #mm
    #     p300.aspirate(mmix_XFR_std_mix, MIX_master.bottom(mmix_h[i])) # 18 * 3 * 1.12-0.05= 54 + 6 =60ul
    #     protocol.delay(seconds=2) #tip equilibrate
    #     p300.move_to(MIX_master.bottom(35)) # excess tip fluid condense
    #     protocol.delay(seconds=3) #tip droplets slide
    #     p300.touch_tip(v_offset=-2)
    #     p300.dispense(mmix_XFR_std_mix, tube.bottom(4))
    #     p300.blow_out(tube.bottom(8))
    # p300.drop_tip()
    # p300.flow_rate.aspirate = 92.86 #reset to default
    # p300.flow_rate.dispense = 92.86 #reset to 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=2) #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(3))
    #     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.bottom(2))
    #         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))
    #         protocol.delay(seconds=2)
    #         p20.move_to(plate[dest].bottom(6))
    #         p20.blow_out()
    #         # p20.touch_tip()
    #     p300.drop_tip()
    #     p20.drop_tip()
    # p20.flow_rate.aspirate = 7.56
    # p20.flow_rate.dispense = 7.56

    # # transfer mastermix bolus to beginning wells to receive sample
    # samp_h = tip_heightsEpp(mix_master_tot-mmix_XFR_std_mix, len(samp_wells), mmix_XFR_samp_wells)
    # p300.pick_up_tip()
    # for i, well in enumerate(samp_wells):
    #     vols = split_asp(mmix_XFR_samp_wells, p300_max_vol) #split 237.60 into 2 asp steps
    #     for j, vol in enumerate(vols): # loop through each vol
    #         p300.flow_rate.aspirate = 40 #default
    #         p300.flow_rate.dispense = 40 #default
    #         p300.aspirate(vol, MIX_master.bottom(samp_h[i]))
    #         protocol.delay(seconds=2)
    #         p300.dispense(vol, plate[well].bottom(4*j+5))
    #         protocol.delay(seconds=1)
    #         p300.blow_out(plate[well].bottom(14))
    #         p300.touch_tip()
    # p300.drop_tip()

    # add dna to first wells, mix, and aliquot to neighbors
    # six samples, can be changed in the user inputs
    samp_dna_XFR_to_wells = 2 * 12 * 1.1  # 26.4 2ul in 12 wells + excess
    for i, (sample, well) in enumerate(zip(samp_sources, samp_wells)):
        p300.pick_up_tip()
        p20.pick_up_tip()
        p300.flow_rate.aspirate = 92.86
        p300.flow_rate.dispense = 92.86
        p300.mix(3, 200, sample)  # mix the sample
        p300.flow_rate.aspirate = 30
        p300.flow_rate.dispense = 40
        p300.aspirate(samp_dna_XFR_to_wells,
                      sample.bottom(2))  # sample vol may vary. Goto bottom.
        p300.move_to(sample.bottom(25))  # relieve pressure if tip at bottom
        protocol.delay(seconds=2)
        p300.touch_tip()
        p300.dispense(samp_dna_XFR_to_wells, plate[well].bottom(3))
        p300.flow_rate.aspirate = 92.86
        p300.flow_rate.dispense = 92.86
        p300.mix(3, 200, plate[well].bottom(5))  # vol = 26.4 + 237.6 = 264
        p300.flow_rate.aspirate = 30
        p300.flow_rate.dispense = 40
        p300.mix(1, 200, plate[well].bottom(3))
        p300.move_to(plate[well].bottom(14))
        protocol.delay(seconds=2)
        p300.blow_out(plate[well].bottom(16))
        p300.touch_tip()
        for x in range(1, 12):  # need int 1, 2, and 12
            # find digits in well, G1 and G10 and puts into list
            findNums = [int(d) for d in well.split()[0] if d.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.flow_rate.aspirate = 7.56
            p20.flow_rate.dispense = 7.56
            p20.aspirate(20, plate[well])
            p20.move_to(plate[well].bottom(16))
            protocol.delay(seconds=2)  #equilibrate
            p20.touch_tip()
            p20.dispense(20, plate[dest].bottom(2))
            protocol.delay(seconds=1)
            # p20.move_to(plate[dest].bottom(4))
            p20.blow_out(plate[dest].bottom(6))
        p20.drop_tip()
        p300.drop_tip()
def run(ctx: protocol_api.ProtocolContext):

    # Initial data
    global robot
    global tip_log

    # Set robot as global var
    robot = ctx

    # check if tipcount is being reset
    if RESET_TIPCOUNT:
        reset_tipcount()

    # confirm door is close
    robot.comment(f"Please, close the door")
    confirm_door_is_closed()

    start = start_run()

    # #####################################################
    # Common functions
    # #####################################################

    # -----------------------------------------------------
    # Execute step
    # -----------------------------------------------------
    def run_step(step):

        robot.comment(' ')
        robot.comment('###############################################')
        robot.comment('Step ' + str(step) + ': ' + STEPS[step]['Description'])
        robot.comment('===============================================')

        # Execute step?
        if STEPS[step]['Execute']:

            # Get start info
            elapsed = datetime.now()
            for i, key in enumerate(tip_log['used']):
                val = tip_log['used'][key]
                if i == 0:
                    cl = val
                else:
                    cr = val

            # Execute function step
            STEPS[step]['Function']()

            # Wait
            if STEPS[step].get('wait_time'):
                robot.comment(
                    '===============================================')
                wait = STEPS[step]['wait_time']
                robot.delay(seconds=wait)

            # Get end info
            elapsed = datetime.now() - elapsed
            for i, key in enumerate(tip_log['used']):
                val = tip_log['used'][key]
                if i == 0:
                    cl = val - cl
                else:
                    cr = val - cr
            # Stats
            STEPS[step]['Time:'] = str(elapsed)
            robot.comment('===============================================')
            robot.comment('Elapsed time: ' + str(elapsed))
            for i, key in enumerate(tip_log['used']):
                if i == 0:
                    robot.comment('Tips "' + str(key) + '" used: ' + str(cl))
                else:
                    robot.comment('Tips "' + str(key) + '" used: ' + str(cr))

        # Dont execute step
        else:
            robot.comment('No ejecutado')

        # End
        robot.comment('###############################################')
        robot.comment(' ')

    # #####################################################
    # 1. Start defining deck
    # #####################################################

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

    # -----------------------------------------------------
    # Tips
    # -----------------------------------------------------

    tips20 = [
        robot.load_labware('opentrons_96_filtertiprack_20ul', slot)
        for slot in ['11']
    ]

    # -----------------------------------------------------
    # Pipettes
    # -----------------------------------------------------

    p20 = robot.load_instrument('p20_single_gen2', 'right', tip_racks=tips20)

    ## retrieve tip_log

    retrieve_tip_info(p20, tips20)

    # -----------------------------------------------------
    # Labware
    # -----------------------------------------------------

    positive_control_rack = ctx.load_labware(
        'opentrons_24_tuberack_nest_2ml_screwcap', '7',
        '24_tuberack_starsted source rack')

    dest_rack = ctx.load_labware(
        'opentrons_96_aluminumblock_biorad_wellplate_200ul', '8',
        'source tuberack ')

    # -----------------------------------------------------
    # Reagens
    # -----------------------------------------------------
    positive_control_master_mix = Reagent(name='Positive control Master Mix',
                                          flow_rate_aspirate=600,
                                          flow_rate_dispense=1000,
                                          flow_rate_aspirate_mix=600,
                                          flow_rate_dispense_mix=1000)

    # -----------------------------------------------------
    # Tubes
    # -----------------------------------------------------
    starsted_tube = Tube(
        name='Starsted 1.5 Tube',
        actual_volume=400,
        max_volume=1500,
        min_height=0.7,
        diameter=8.7,  # avl1.diameter
        base_type=2,
        height_base=4)

    # #####################################################
    # 2. Steps definition
    # #####################################################

    # -----------------------------------------------------
    # Step n: ....
    # -----------------------------------------------------
    def step1():

        if not p20.hw_pipette['has_tip']:
            pick_up(p20, tips20)

        segene_positive_control_mastermix = positive_control_rack['A6']

        dest = dest_rack.wells()[:50]

        # transfer buffer to tubes
        distribute_custom(pip=p20,
                          reagent=positive_control_master_mix,
                          tube_type=starsted_tube,
                          volume=15,
                          src=segene_positive_control_mastermix,
                          dest=dest,
                          extra_dispensal=0,
                          disp_height=20,
                          touch_tip_aspirate=False,
                          touch_tip_dispense=True)

        drop(p20)

    # -----------------------------------------------------
    # Execution plan
    # -----------------------------------------------------
    STEPS = {
        1: {
            'Execute': True,
            'Function': step1,
            'Description': 'Transfer Primers 20 first wells/tubes'
        },
    }

    # #####################################################
    # 3. Execute every step!!
    # #####################################################
    for step in STEPS:
        run_step(step)

    # track final used tip
    save_tip_info()

    # -----------------------------------------------------
    # Stats
    # -----------------------------------------------------
    end = finish_run()

    robot.comment('===============================================')
    robot.comment('Start time:   ' + str(start))
    robot.comment('Finish time:  ' + str(end))
    robot.comment('Elapsed time: ' + str(
        datetime.strptime(end, "%Y/%m/%d %H:%M:%S") -
        datetime.strptime(start, "%Y/%m/%d %H:%M:%S")))
    for key in tip_log['used']:
        val = tip_log['used'][key]
        robot.comment('Tips "' + str(key) + '" used: ' + str(val))
    robot.comment('===============================================')
def run(protocol: protocol_api.ProtocolContext):
    """
    Aliquoting mastermix from a 5 mL tube to 5x + 2 wells PCR strips in 
    2x 96-wells plates; using volume tracking so that the pipette starts 
    aspirating at the starting height of the liquid and goes down as the 
    volume decreases.
    Adding primers from PCR strips (with 10 uM primer F&R primer mix)
    to PCR strips (with mastermix).
    """
    # =============================================================================

    # ======================LOADING LABWARE AND PIPETTES===========================
    # =============================================================================
    ## For available labware see "labware/list_of_available_labware".       ##
    # Pipette tips
    tips_200 = protocol.load_labware(
        'opentrons_96_filtertiprack_200ul',  #labware definition
        3,  #deck position
        '200tips')  #custom name
    tips_20 = protocol.load_labware(
        'opentrons_96_filtertiprack_20ul',  #labware definition
        4,  #deck position
        '20tips')  #custom name

    # Tube racks & plates
    ##### !!! OPTION 1: ROBOT
    # mastermix_tube = protocol.load_labware(
    #     'eppendorfscrewcap_15_tuberack_5000ul', #labware def
    #      5,                                     #deck position
    #      'mastermix_tube')                             #custom name
    # primer_strips_1 = protocol.load_labware(
    #     'pcrstrips_96_wellplate_200ul',    #labware definition
    #     6,                                 #deck position
    #     'primer_strips_1')                 #custom name
    # primer_strips_2 = protocol.load_labware(
    #     'pcrstrips_96_wellplate_200ul',    #labware definition
    #     7,                                 #deck position
    #     'primer_strips_2')                 #custom name
    # mastermix_strips_1 = protocol.load_labware(
    #     'pcrstrips_96_wellplate_200ul',    #labware definition
    #     8,                                 #deck position
    #     'mastermix_strips_1')                    #custom name
    # mastermix_strips_2 = protocol.load_labware(
    #     'pcrstrips_96_wellplate_200ul',    #labware definition
    #     9,                                 #deck position
    #     'mastermix_strips_2')                    #custom name
    ##### !!! OPTION 2: SIMULATOR
    with open("labware/eppendorfscrewcap_15_tuberack_5000ul/"
              "eppendorfscrewcap_15_tuberack_5000ul.json") as labware_file:
        labware_def_5mL = json.load(labware_file)
    mastermix_tube = protocol.load_labware_from_definition(
        labware_def_5mL,  #variable derived from opening json
        5,  #deck position
        'mastermix_tube')  #custom name
    with open("labware/pcrstrips_96_wellplate_200ul/"
              "pcrstrips_96_wellplate_200ul.json") as labware_file:
        labware_def_pcrstrips = json.load(labware_file)
    primer_strips_1 = protocol.load_labware_from_definition(
        labware_def_pcrstrips,  #variable derived from opening json
        6,  #deck position
        'primer_strips_1')  #custom name
    primer_strips_2 = protocol.load_labware_from_definition(
        labware_def_pcrstrips,  #variable derived from opening json
        7,  #deck position
        'primer_strips_2')  #custom name
    mastermix_strips_1 = protocol.load_labware_from_definition(
        labware_def_pcrstrips,  #variable derived from opening json
        8,  #deck position
        'mastermix_strips_1')  #custom name
    mastermix_strips_2 = protocol.load_labware_from_definition(
        labware_def_pcrstrips,  #variable derived from opening json
        9,  #deck position
        'mastermix_strips_2')  #custom name

    # Pipettes
    p300 = protocol.load_instrument(
        'p300_single_gen2',  #instrument definition
        'right',  #mount position
        tip_racks=[tips_200])  #assigned tiprack
    p20 = protocol.load_instrument(
        'p20_single_gen2',  #instrument definition
        'left',  #mount position
        tip_racks=[tips_20])  #assigned tiprack
    # =============================================================================

    # ==========================VARIABLES TO SET#!!!===============================
    # =============================================================================
    start_vol = 1974
    ## The start_vol is the volume (ul) that is in the source labware at  ##
    ## the start of the protocol.                                         ##
    dispension_vol = 42
    ## The dispension_vol is the volume (ul) that needs to be aliquoted   ##
    ## into the destination wells/tubes.                                  ##
    primer_vol = 3
    ## The sample_vol is the volume (ul) of sample added to the PCR       ##
    ## reaction.                                                          ##
    p300.starting_tip = tips_200.well('A1')
    p20.starting_tip = tips_20.well('A1')
    ## The starting_tip is the location of first pipette tip in the box   ##
    container = 'tube_5mL'
    ## The container variable is needed for the volume tracking module.   ##
    ## It tells the module which dimensions to use for the calculations   ##
    ## of the pipette height. It is the source labware from which liquid  ##
    ## is aliquoted.                                                      ##
    ## There are several options to choose from:                          ##
    ## 'tube_1.5ml', 'tube_2mL', 'tube_5mL', 'tube_15mL', 'tube_50mL'   	##
    mastermix_source = mastermix_tube['C1']
    # Mastermix destination wells==================================================
    mastermix = []
    ## Create an empty list to append wells to                            ##
    mastermix_columns = ([
        mastermix_strips_1.columns_by_name()[column_name]
        for column_name in ['2', '7', '11']
    ] + [
        mastermix_strips_2.columns_by_name()[column_name]
        for column_name in ['2', '7']
    ])
    ## Make a list of columns, this is a list of lists!                   ##
    for column in mastermix_columns:
        for well in column:
            mastermix.append(well)
    ## Separate the columns into wells and append them to list            ##
    mastermix_wells = ([
        mastermix_strips_2.wells_by_name()[well_name]
        for well_name in ['A11', 'B11']
    ])
    ## Make a list of separate wells                                      ##
    for well in mastermix_wells:
        mastermix.append(well)
    ## Append the wells to the list                                       ##
# Primer source tubes==========================================================
    primers = []
    ## Create an empty list to append wells to                            ##
    primer_columns = ([
        primer_strips_1.columns_by_name()[column_name]
        for column_name in ['2', '7', '11']
    ] + [
        primer_strips_2.columns_by_name()[column_name]
        for column_name in ['2', '7']
    ])
    ## Make a list of columns, this is a list of lists!                   ##
    for column in primer_columns:
        for well in column:
            primers.append(well)
    ## Separate the columns into wells and append them to list            ##
    primer_wells = ([
        primer_strips_2.wells_by_name()[well_name]
        for well_name in ['A11', 'B11']
    ])
    ## Make a list of separate wells                                      ##
    for well in primer_wells:
        primers.append(well)
    ## Append the wells to the list                                       ##
# =============================================================================
# =============================================================================

# ==========================PREDIFINED VARIABLES===============================
# =============================================================================
    aspiration_vol = dispension_vol + (dispension_vol / 100 * 2)
    ## The aspiration_vol is the volume (ul) that is aspirated from the   ##
    ## container.                                                         ##
    ##### Variables for volume tracking
    start_height = vt.cal_start_height(container, start_vol)
    ## Call start height calculation function from volume tracking module.##
    current_height = start_height
    ## Set the current height to start height at the beginning of the     ##
    ## protocol.                                                          ##
    # =============================================================================

    # ===============================ALIQUOTING MIX================================
    # =============================================================================
    ## For each column in destination_wells, pick up a tip, than for each   ##
    ## well in these columns pipette mix, and after the+ column drop the tip##
    ## Repeat untill all columns in the list are done.                      ##
    for i, well in enumerate(mastermix):
        ## Name all the wells in the plate 'well', for all these do:            ##
        if i == 0:
            p300.pick_up_tip()
        ## If we are at the first well, start by picking up a tip.        ##
        elif i % 8 == 0:
            p300.drop_tip()
            p300.pick_up_tip()
        ## Then, after every 8th well, drop tip and pick up a new one.    ##
        current_height, pip_height, bottom_reached = vt.volume_tracking(
            container, dispension_vol, current_height)
        ## The volume_tracking function needs the arguments container,    ##
        ## dispension_vol, and the current_height which we have set in    ##
        ## this protocol. With those variables, the function updates      ##
        ## the current_height, the pip_height and calculates the          ##
        ## delta_height of the liquid after the next aspiration step.     ##
        if bottom_reached:
            aspiration_location = mastermix_source.bottom(z=1)  #!!!
            protocol.comment("You've reached the bottom!")
        else:
            aspiration_location = mastermix_source.bottom(pip_height)  #!!!
        ## If the level of the liquid in the next run of the loop will    ##
        ## be smaller than 1 we have reached the bottom of the tube.      ##
        ## To prevent the pipette from crashing into the bottom, we       ##
        ## tell it to go home and pause the protocol so that this can     ##
        ## never happen. Set the location of where to aspirate from.      ##
        ## Because we put this in the loop, the location will change      ##
        ## to the newly calculated height after each pipetting step.      ##
        p300.aspirate(aspiration_vol, aspiration_location)
        ## Aspirate the amount specified in aspiration_vol from the       ##
        ## location specified in aspiration_location.                     ##
        p300.dispense(dispension_vol, well)
        ## Dispense the amount specified in dispension_vol to the         ##
        ## location specified in well (so a new well every time the       ##
        ## loop restarts)                                                 ##
        p300.dispense(10, aspiration_location)
        ## Alternative for blow-out, make sure the tip doesn't fill       ##
        ## completely when using a disposal volume by dispensing some     ##
        ## of the volume after each pipetting step. (blow-out to many     ##
        ## bubbles)                                                       ##
    p300.drop_tip()
    # =============================================================================

    # ===============================ADDING PRIMERS================================
    # =============================================================================
    ## For the columns in both the source (primers) and the destination     ##
    ## (mix): loop trough the wells in those columns.                       #
    for primer_tube, mix_tube in zip(primers, mastermix):
        p20.pick_up_tip()
        p20.aspirate(primer_vol, primer_tube)
        p20.dispense(primer_vol, mix_tube)
        primer_mix_vol = primer_vol + 3
        ## primer_mix_vol = volume for pipetting up and down                ##
        p20.mix(3, primer_mix_vol, mix_tube)
        p20.dispense(10, mix_tube)
        p20.drop_tip()
Example #24
0
def run(protocol: protocol_api.ProtocolContext):
    """
    Alliquoting MasterMix
    Adding samples from 1.5 mL tubes to PCR_strips or plate.
    different DNA volumes + water to add up
    """
# =============================================================================

# LOADING LABWARE AND PIPETTES=================================================
# =============================================================================
    ## For available labware see "labware/list_of_available_labware".        ##
    
    #pipette tips
    tips_200 = protocol.load_labware(
        'opentrons_96_filtertiprack_200ul', #labware definition
        9,                                  #deck position
        '200tips')                          #custom name
    
    tips_20_1 = protocol.load_labware(
        'opentrons_96_filtertiprack_20ul',  #labware definition
        3,                                  #deck position
        '20tips_1')                         #custom name       
    tips_20_2 = protocol.load_labware(
        'opentrons_96_filtertiprack_20ul',  #labware definition
        6,                                 #deck position
        '20tips_2')                         #custom name

    # Tube_racks & plates
    sample_tubes_1 = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',#labware def
        1,                                                       #deck position
        'sample_tubes_1')                                        #custom name
    if sample_racks >= 2:
        sample_tubes_2 = protocol.load_labware(
            'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',#labw def
            4,                                                       #deck pos
            'sample_tubes_2')                                        #cust name
    if sample_racks >= 3:
        sample_tubes_3 = protocol.load_labware(
            'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',#labw def
            7,                                                       #deck pos
            'sample_tubes_3')                                        #cust name
    if sample_racks >= 4:
        sample_tubes_4 = protocol.load_labware(
            'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',#labw def
            10,                                                      #deck pos
            'sample_tubes_4')                                        #cust name
   
    if PCR_tubes == 'plate_96': 
        PCR_1 = protocol.load_labware(
        'biorad_96_wellplate_200ul_pcr',    #labware definition
        2,                                  #deck position
        'plate_96')                         #custom name
    
    if PCR_tubes == 'PCR_strips':
   ### !!! OPTION 1: ROBOT         
        # PCR_1 = protocol.load_labware(
        #   'pcrstrips_96_wellplate_200ul',    #labware definition
        #   2,                                 #deck position
        #   'PCR_tube_1')                      #custom name
        # if PCR_racks >= 2:
        #     PCR_2 = protocol.load_labware(
        #           'pcrstrips_96_wellplate_200ul',    #labware definition
        #           5,                                 #deck position
        #           'PCR_tube_2')                      #custom name
        # if PCR_racks >= 3:
        #     PCR_3 = protocol.load_labware(
        #           'pcrstrips_96_wellplate_200ul',    #labware definition
        #           8,                                 #deck position
        #           'PCR_tube_3')                      #custom name
 
    ##### !!! OPTION 2: SIMULATOR         
        with open("labware/pcrstrips_96_wellplate_200ul/"
                    "pcrstrips_96_wellplate_200ul.json") as labware_file:
                  labware_def_pcrstrips = json.load(labware_file)
        PCR_1 = protocol.load_labware_from_definition( 
              labware_def_pcrstrips, #variable derived from opening json
              2,                     #deck position
              'PCR_tube_1')          #custom name
        if PCR_racks >= 2:
            PCR_2 = protocol.load_labware_from_definition( 
                  labware_def_pcrstrips, #variable derived from opening json
                  5,                     #deck position
                  'PCR_tube_2')          #custom name
        if PCR_racks >= 3:
            PCR_3 = protocol.load_labware_from_definition( 
                  labware_def_pcrstrips, #variable derived from opening json
                  8,                     #deck position
                  'PCR_tube_2')          #custom name


    ##### !!! OPTION 1: ROBOT
    # tubes_5mL = protocol.load_labware(
    #     'eppendorfscrewcap_15_tuberack_5000ul', #labware def
    #     11,                                     #deck position
    #     'tubes_5mL')                            #custom name 
   ##### !!! OPTION 2: SIMULATOR      
    with open("labware/eppendorfscrewcap_15_tuberack_5000ul/"
                "eppendorfscrewcap_15_tuberack_5000ul.json") as labware_file:
              labware_def_5mL = json.load(labware_file)
    tubes_5mL = protocol.load_labware_from_definition( 
        labware_def_5mL,   #variable derived from opening json
        11,                 #deck position
        'tubes_5mL')  #custom name 
    
    # Pipettes
    p20 = protocol.load_instrument(
        'p20_single_gen2',                  #instrument definition
        'left',                             #mount position
        tip_racks=[tips_20_1, tips_20_2])   #assigned tiprack
    p300 = protocol.load_instrument(
        'p300_single_gen2',                 #instrument definition
        'right',                            #mount position
        tip_racks=[tips_200])               #assigned tiprack    
# =============================================================================

# PREDIFINED VARIABLES=========================================================
# =============================================================================
    ##### Mastermix
    aspiration_vol = dispension_vol + (dispension_vol/100*2)
      ## The aspiration_vol is the volume (ul) that is aspirated from the    ##
      ## container.                                                          ##
    MM_start_height = vt.cal_start_height('tube_5mL', start_vol_MM)
      ## Call start height calculation function from volume tracking module. ##
    MM_current_height = MM_start_height
      ## Set the current height to start height at the beginning of the      ##
      ## protocol.                                                           ##
    
    ##### Water
    w_start_height = vt.cal_start_height('tube_5mL', start_vol_w)
      ## Call start height calculation function from volume tracking module. ##
    w_current_height = w_start_height
      ## Set the current height to start height at the beginning of the      ##
      ## protocol.                                                           ## 
# =============================================================================

# SETTING LOCATIONS============================================================
# =============================================================================
    ##### Setting starting tip                                               ##
    p300.starting_tip = tips_200.well(starting_tip_p200)
    p20.starting_tip = tips_20_1.well(starting_tip_p20)
      ## The starting_tip is the location of first pipette tip in the box    ##

    # Sample source wells
    sample_sources = []
      ## Create an empty list to append wells to.                            ##
    sample_sources = sample_tubes_1.wells()
    if sample_racks >= 2:
        sample_sources = sample_sources + sample_tubes_2.wells()
    if sample_racks >= 3:
        sample_sources = sample_sources + sample_tubes_3.wells()    
    if sample_racks >= 4:
        sample_sources = sample_sources + sample_tubes_4.wells()
    sample_sources = sample_sources[:number_of_samples]
    
    # Destination wells
    sample_destinations = []
      ## Create an empty list to append wells to.                            ##
    if PCR_tubes == 'plate_96':
        sample_destinations = PCR_1.wells()
    elif PCR_tubes == 'PCR_strips':
        PCR_columns = (
            ([PCR_1.columns_by_name()[column_name]
            for column_name in strip_positions]))        
        if PCR_racks >= 2:
            PCR_columns_2 = (
            ([PCR_2.columns_by_name()[column_name]
              for column_name in strip_positions]))
            PCR_columns = PCR_columns + PCR_columns_2
        if PCR_racks >= 3:
            PCR_columns_3 = (
            ([PCR_3.columns_by_name()[column_name]
              for column_name in strip_positions]))
            PCR_columns = PCR_columns + PCR_columns_3
        for column in PCR_columns:
            for well in column:
                sample_destinations.append(well)
                
    sample_destinations = sample_destinations[:number_of_samples]

    ##### Tube locations                                                     ##
    MasterMix = tubes_5mL[mastermix_source]
      ## Location of the 5mL tube with mastermix                             ##
    water = tubes_5mL[water_tube]       
      ## Location of the 5mL tube with water                                 ##

## ALIQUOTING MASTERMIX========================================================
## ============================================================================
    for i, well in enumerate(sample_destinations):
      ## aliquot mix, for each well do the following:                       ##
        if i == 0: 
            p300.pick_up_tip()
              ## If we are at the first well, start by picking up a tip.    ##
        elif i % 16 == 0:
            p300.drop_tip()
            p300.pick_up_tip()
              ## Then, after every 16th well, drop tip and pick up new       ##
    
        MM_current_height, pip_height, bottom_reached = vt.volume_tracking(
                'tube_5mL', dispension_vol, MM_current_height)
                  ## call volume_tracking function, obtain current_height,  ##
                  ## pip_height and whether bottom_reached.                 ##
        
        if bottom_reached:
            aspiration_location = MasterMix.bottom(z=1)
            protocol.comment("You've reached the bottom of the tube!")
              ## If bottom is reached keep pipetting from bottom + 1        ##
        else:
            aspiration_location = MasterMix.bottom(pip_height)
              ## Set the location of where to aspirate from.                ##

        #### The actual aliquoting of mastermix                             ##
        p300.aspirate(aspiration_vol, aspiration_location)
          ## Aspirate the amount specified in aspiration_vol from the       ##
          ## location specified in aspiration_location.                     ##
        p300.dispense(dispension_vol, well)
          ## Dispense the amount specified in dispension_vol to the         ##
          ## location specified in well (so a new well every time the       ##
          ## loop restarts)                                                 ##
        p300.dispense(10, aspiration_location)
          ## Alternative for blow-out, make sure the tip doesn't fill       ##
          ## completely when using a disposal volume by dispensing some     ##
          ## of the volume after each pipetting step. (blow-out to many     ##
          ## bubbles)                                                       ##
    p300.drop_tip()      
# =============================================================================

# ADDING SAMPLES AND WATER=====================================================
# =============================================================================
    ## Loop through source and destination wells
    for sample_tube, well, sample_vol in zip(
            sample_sources, sample_destinations, DNA_µL_list
            ):
        if sample_vol > 0:
            p20.pick_up_tip()
            p20.aspirate(sample_vol, sample_tube)
            p20.dispense(sample_vol, well)
            sample_mix_vol = sample_vol + 3
              ## mix_vol = volume for pipetting up and down                  ##
            p20.mix(3, sample_mix_vol, well)
            p20.dispense(10, well)
            p20.drop_tip()
        
        water_vol = max_DNA_volume - sample_vol
          ## volume of water needed to add a total of max_DNA_volume
        if water_vol > 0:
            
            w_current_height, pip_height, bottom_reached = vt.volume_tracking(
                    'tube_5mL', water_vol, w_current_height)
                   ## call volume_tracking function, obtain current_height,  ##
                   ## pip_height and whether bottom_reached.                 ##
            if bottom_reached:
                aspiration_location = water.bottom(z=1)
                protocol.comment("You've reached the bottom of the tube!")
                  ## If bottom is reached keep pipetting from bottom + 1     ##
            else:
                aspiration_location = water.bottom(pip_height)
                  ## Set the location of where to aspirate from.             ##
            
            p20.pick_up_tip()
            p20.aspirate(water_vol, aspiration_location)
            p20.dispense(water_vol, well)
            mix_vol = water_vol + 3
              ## mix_vol = volume for pipetting up and down                  ##
            p20.mix(3, mix_vol, well)
            p20.dispense(10, well)
            p20.drop_tip()
def run(ctx: protocol_api.ProtocolContext):
    source_plate = ctx.load_labware('nest_96_wellplate_100ul_pcr_full_skirt',
                                    '1', 'RNA elution plate from station B')
    pcr_plate = ctx.load_labware('nest_96_wellplate_100ul_pcr_full_skirt', '2',
                                 'PCR plate')
    tuberack = ctx.load_labware(
        'opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap', '5',
        '2ml Eppendorf tuberack')
    tips20 = [
        ctx.load_labware('opentrons_96_filtertiprack_20ul', slot)
        for slot in ['3', '6', '9']
    ]

    # pipette
    p20 = ctx.load_instrument('p20_single_gen2', 'right', tip_racks=tips20)

    # setup up sample sources and destinations
    samples = source_plate.wells()[:NUM_SAMPLES]
    sample_dest_sets = [
        row[i * 3:(i + 1) * 3] for i in range(12 // 3)
        for row in pcr_plate.rows()
    ][:NUM_SAMPLES]
    mm = tuberack.rows()[0][:3]
    mm_dests = [[well for col in pcr_plate.columns()[j::3]
                 for well in col][:NUM_SAMPLES] +
                pcr_plate.columns()[9 + j][-2:] for j in range(3)]
    pos_control = tuberack.rows()[1][0]
    pos_control_dests = pcr_plate.rows()[-2][-1 * 3:]
    neg_control = tuberack.rows()[1][1]
    neg_control_dests = tuberack.rows()[-1][-1 * 3:]

    # transfer mastermixes
    for s, d_set in zip(mm, mm_dests):
        p20.transfer(15, s, d_set)

    # transfer samples to corresponding locations
    for s, d_set in zip(samples, sample_dest_sets):
        for d in d_set:
            p20.pick_up_tip()
            p20.transfer(5, s, d, new_tip='never')
            p20.mix(1, 10, d)
            p20.blow_out(d.top(-2))
            p20.aspirate(5, d.top(2))
            p20.drop_tip()

    # transfer controls
    for d in pos_control_dests:
        p20.pick_up_tip()
        p20.transfer(5, pos_control, d, new_tip='never')
        p20.mix(1, 10, d)
        p20.blow_out(d.top(-2))
        p20.aspirate(5, d.top(2))
        p20.drop_tip()

    for d in neg_control_dests:
        p20.pick_up_tip()
        p20.transfer(5, neg_control, d, new_tip='never')
        p20.mix(1, 10, d)
        p20.blow_out(d.top(-2))
        p20.aspirate(5, d.top(2))
        p20.drop_tip()
Example #26
0
def run(protocol: protocol_api.ProtocolContext):
    """
    Adding samples from 1.5 mL tubes or PCR_strips to a 96 wells plate.
    """
    # =============================================================================

    # LOADING LABWARE AND PIPETTES=================================================
    # =============================================================================
    ## For available labware see "labware/list_of_available_labware".       ##

    #pipette tips
    tips_20_1 = protocol.load_labware(
        'opentrons_96_filtertiprack_20ul',  #labware definition
        7,  #deck position
        '20tips_1')  #custom name
    tips_20_2 = protocol.load_labware(
        'opentrons_96_filtertiprack_20ul',  #labware definition
        10,  #deck position
        '20tips_2')  #custom name

    # Tube_racks & plates
    if sample_tubes == 'tubes_1.5mL':
        sample_tubes_1 = protocol.load_labware(
            'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',  #labware def
            4,  #deck position
            'sample_tubes_1')  #custom name
        if sample_racks >= 2:
            sample_tubes_2 = protocol.load_labware(
                'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',  #labw def
                1,  #deck pos
                'sample_tubes_2')  #cust name
        if sample_racks >= 3:
            sample_tubes_3 = protocol.load_labware(
                'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',  #labw def
                3,  #deck pos
                'sample_tubes_3')  #cust name
        if sample_racks >= 4:
            sample_tubes_4 = protocol.load_labware(
                'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap',  #labw def
                11,  #deck pos
                'sample_tubes_4')  #cust name

    if sample_tubes == 'PCR_strips':
        ##### !!! OPTION 1: ROBOT
        sample_strips_1 = protocol.load_labware(
            'pcrstrips_96_wellplate_200ul',  #labware definition
            4,  #deck position
            'sample_strips_1')  #custom name
        if sample_racks >= 2:
            sample_strips_2 = protocol.load_labware(
                'pcrstrips_96_wellplate_200ul',  #labware definition
                1,  #deck position
                'sample_strips_2')  #custom name
        if sample_racks >= 3:
            sample_strips_3 = protocol.load_labware(
                'pcrstrips_96_wellplate_200ul',  #labware definition
                3,  #deck position
                'sample_strips_3')  #custom name
        if sample_racks >= 4:
            sample_strips_4 = protocol.load_labware(
                'pcrstrips_96_wellplate_200ul',  #labware definition
                11,  #deck position
                'sample_strips_4')  #custom name
##### !!! OPTION 2: SIMULATOR
# with open("labware/pcrstrips_96_wellplate_200ul/"
#           "pcrstrips_96_wellplate_200ul.json") as labware_file:
#         labware_def_pcrstrips = json.load(labware_file)
# sample_strips_1 = protocol.load_labware_from_definition(
#     labware_def_pcrstrips, #variable derived from opening json
#     4,                     #deck position
#     'sample_strips_1')     #custom name
# if sample_racks >= 2:
#     sample_strips_2 = protocol.load_labware_from_definition(
#         labware_def_pcrstrips, #variable derived from opening json
#         1,                     #deck position
#         'sample_strips_2')     #custom name
# if sample_racks >= 3:
#     sample_strips_3 = protocol.load_labware_from_definition(
#         labware_def_pcrstrips, #variable derived from opening json
#         3,                    #deck position
#         'sample_strips_3')     #custom name
# if sample_racks >= 4:
#     sample_strips_4 = protocol.load_labware_from_definition(
#         labware_def_pcrstrips, #variable derived from opening json
#         11,                    #deck position
#         'sample_strips_4')     #custom name

##### !!! OPTION 1: ROBOT
    plate_96 = protocol.load_labware(
        'biorad_qpcr_plate_eppendorf_cool_rack',  #labware definition
        5,  #deck position
        '96well_plate_rack')  #custom name
    ##### !!! OPTION 2: SIMULATOR
    # with open("labware/biorad_qpcr_plate_eppendorf_cool_rack/"
    #             "biorad_qpcr_plate_eppendorf_cool_rack.json") as labware_file:
    #           labware_def_cool_rack = json.load(labware_file)
    # plate_96 = protocol.load_labware_from_definition(
    #     labware_def_cool_rack,   #variable derived from opening json
    #     5,                       #deck position
    #     '96well_plate_rack')     #custom name

    # Pipettes
    p20 = protocol.load_instrument(
        'p20_single_gen2',  #instrument definition
        'left',  #mount position
        tip_racks=[tips_20_1, tips_20_2])  #assigned tiprack

    # =============================================================================

    # PREDIFINED VARIABLES=========================================================
    # =============================================================================
    p20.starting_tip = tips_20_1.well(starting_tip_p20)
    ## The starting_tip is the location of first pipette tip in the box   ##

    # Sample source wells
    sample_sources = []
    ## Create an empty list to append wells to.                           ##
    if sample_tubes == 'tubes_1.5mL':
        sample_sources = sample_tubes_1.wells()
        if sample_racks >= 2:
            sample_sources = sample_sources + sample_tubes_2.wells()
        if sample_racks >= 3:
            sample_sources = sample_sources + sample_tubes_3.wells()
        if sample_racks >= 4:
            sample_sources = sample_sources + sample_tubes_4.wells()
        sample_sources = sample_sources[:number_of_samples]

        if std_sample:
            std_source = [sample_sources[-1]] * (no_of_std_samples - 1)
            for well in std_source:
                sample_sources.append(well)
            ## adds the same well (where the std_sample is) to the sample   ##
            ## sources list, so will pipete no_of_std_samples times from    ##
            ## the same well                                                ##
    if sample_tubes == 'PCR_strips':
        sample_columns = (([
            sample_strips_1.columns_by_name()[column_name]
            for column_name in strip_positions
        ]))
        if sample_racks >= 2:
            sample_columns2 = (([
                sample_strips_2.columns_by_name()[column_name]
                for column_name in strip_positions
            ]))
            for column in sample_columns2:
                sample_columns.append(column)
        if sample_racks >= 3:
            sample_columns3 = (([
                sample_strips_3.columns_by_name()[column_name]
                for column_name in strip_positions
            ]))
            for column in sample_columns3:
                sample_columns.append(column)
        if sample_racks >= 4:
            sample_columns4 = (([
                sample_strips_4.columns_by_name()[column_name]
                for column_name in strip_positions
            ]))
            for column in sample_columns4:
                sample_columns.append(column)
            ## Make a list of columns, this is a list of lists!             ##

        for column in sample_columns:
            for well in column:
                sample_sources.append(well)
        sample_sources = sample_sources[:number_of_samples]
        ## Separate the columns into wells and append them to list        ##

# ADDING SAMPLES===============================================================
# =============================================================================
## Loop through source and destination wells
    for sample_tube, well in zip(sample_sources, plate_96.wells()):
        p20.pick_up_tip()
        p20.aspirate(sample_vol, sample_tube)
        p20.dispense(sample_vol, well)
        sample_mix_vol = sample_vol + 3
        ## primer_mix_vol = volume for pipetting up and down              ##
        p20.mix(3, sample_mix_vol, well)
        p20.dispense(10, well)
        p20.drop_tip()
Example #27
0
def run(protocol: protocol_api.ProtocolContext):
    tiprack = protocol.load_labware(TIPRACK_LOADNAME, TIPRACK_SLOT)
    pipette = protocol.load_instrument(
        PIPETTE_NAME, PIPETTE_MOUNT, tip_racks=[tiprack])

    test_labware = protocol.load_labware_from_definition(
        LABWARE_DEF,
        TEST_LABWARE_SLOT,
        LABWARE_LABEL,
    )

    num_cols = len(LABWARE_DEF.get('ordering', [[]]))
    num_rows = len(LABWARE_DEF.get('ordering', [[]])[0])
    well_locs = uniq([
        'A1',
        '{}{}'.format(chr(ord('A') + num_rows - 1), str(num_cols))])

    pipette.pick_up_tip()

    def set_speeds(rate):
        protocol.max_speeds.update({
            'X': (600 * rate),
            'Y': (400 * rate),
            'Z': (125 * rate),
            'A': (125 * rate),
        })

        speed_max = max(protocol.max_speeds.values())

        for instr in protocol.loaded_instruments.values():
            instr.default_speed = speed_max

    set_speeds(RATE)

    for slot in CALIBRATION_CROSS_SLOTS:
        coordinate = CALIBRATION_CROSS_COORDS[slot]
        location = types.Location(point=types.Point(**coordinate),
                                  labware=None)
        pipette.move_to(location)
        protocol.pause(
            f"Confirm {PIPETTE_MOUNT} pipette is at slot {slot} calibration cross")

    pipette.home()
    protocol.pause(f"Place your labware in Slot {TEST_LABWARE_SLOT}")

    for well_loc in well_locs:
        well = test_labware.well(well_loc)
        all_4_edges = [
            [well._from_center_cartesian(x=-1, y=0, z=1), 'left'],
            [well._from_center_cartesian(x=1, y=0, z=1), 'right'],
            [well._from_center_cartesian(x=0, y=-1, z=1), 'front'],
            [well._from_center_cartesian(x=0, y=1, z=1), 'back']
        ]

        set_speeds(RATE)
        pipette.move_to(well.top())
        protocol.pause("Moved to the top of the well")

        for edge_pos, edge_name in all_4_edges:
            set_speeds(SLOWER_RATE)
            edge_location = types.Location(point=edge_pos, labware=None)
            pipette.move_to(edge_location)
            protocol.pause(f'Moved to {edge_name} edge')

    # go to bottom last. (If there is more than one well, use the last well first
    # because the pipette is already at the last well at this point)
    for well_loc in reversed(well_locs):
        well = test_labware.well(well_loc)
        set_speeds(RATE)
        pipette.move_to(well.bottom())
        protocol.pause("Moved to the bottom of the well")

        pipette.blow_out(well)

    set_speeds(1.0)
    pipette.return_tip()
Example #28
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', '7', '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')
    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
    p20 = ctx.load_instrument('p20_single_gen2', 'right', tip_racks=tips20)
    p300 = ctx.load_instrument('p300_single_gen2', 'left', tip_racks=tips300)
    p300.flow_rate.aspirate = 20

    # setup up sample sources and destinations
    sources = source_plate.wells()[:NUM_SAMPLES]
    sample_dests = pcr_plate.wells()[:NUM_SAMPLES]

    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'][p20] = data['tips20']
                else:
                    tip_log['count'][p20] = 0
                if 'tips300' in data:
                    tip_log['count'][p300] = data['tips300']
                else:
                    tip_log['count'][p300] = 0
        else:
            tip_log['count'] = {p20: 0, p300: 0}
    else:
        tip_log['count'] = {p20: 0, p300: 0}

    tip_log['tips'] = {
        p20: [tip for rack in tips20 for tip in rack.wells()],
        p300: [tip for rack in tips300 for tip in rack.wells()]
    }
    tip_log['max'] = {pip: len(tip_log['tips'][pip]) for pip in [p20, 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:

        for i, (tube, vol) in enumerate(mm_dict['components'].items()):
            comp_vol = vol * (NUM_SAMPLES + 2) * vol_overage
            pip = p300 if comp_vol > 20 else p20
            pick_up(pip)
            num_trans = math.ceil(comp_vol / 160)
            vol_per_trans = comp_vol / num_trans
            for _ in range(num_trans):
                pip.air_gap(20)
                pip.aspirate(vol_per_trans, tube)
                ctx.delay(seconds=3)
                pip.touch_tip(tube)
                pip.air_gap(20)
                pip.dispense(20, mm_tube.top())  # void air gap
                pip.dispense(vol_per_trans, mm_tube.bottom(2))
                pip.dispense(20, mm_tube.top())  # void pre-loaded air gap
                pip.blow_out(mm_tube.top())
                pip.touch_tip(mm_tube)
            if i < len(
                    mm_dict['components'].items()
            ) - 1 or pip == p20:  # only keep tip if last component and p300 in use
                pip.drop_tip()
        mm_total_vol = mm_dict['volume'] * (NUM_SAMPLES + 2) * 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()
        p300.drop_tip()

    # transfer mastermix to TD plate
    mm_vol = mm_dict['volume']
    pick_up(p20)
    for d in sample_dests:
        p20.air_gap(20 - mm_vol)
        p20.aspirate(mm_vol, mm_tube)
        p20.dispense(20, d)
    p20.drop_tip()

    # transfer samples to corresponding locations
    for s, d in zip(sources, sample_dests):
        pick_up(p20)
        p20.air_gap(10)
        p20.aspirate(SAMPLE_VOL, s.bottom(2))
        p20.air_gap(2)
        p20.dispense(2, d.top())  # void air gap
        p20.dispense(10 + SAMPLE_VOL, d.bottom(2))
        p20.mix(1, 10, d.bottom(2))
        p20.blow_out(d.top(-2))
        p20.aspirate(
            5, d.top(2))  # suck in any remaining droplets on way to trash
        p20.drop_tip()

    # transfer positive and negative control
    pos_control = tube_block.wells()[1]
    neg_control = tube_block.wells()[2]
    for s, d in zip([pos_control, neg_control],
                    pcr_plate.wells()[NUM_SAMPLES:NUM_SAMPLES + 2]):
        pick_up(p20)
        p20.air_gap(10)
        p20.aspirate(SAMPLE_VOL, s.bottom(2))
        p20.air_gap(2)
        p20.dispense(2, d.top())  # void air gap
        p20.dispense(10 + SAMPLE_VOL, d.bottom(2))
        p20.mix(1, 10, d.bottom(2))
        p20.blow_out(d.top(-2))
        p20.aspirate(
            5, d.top(2))  # suck in any remaining droplets on way to trash
        p20.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'][p20],
            'tips300': tip_log['count'][p300]
        }
        with open(tip_file_path, 'w') as outfile:
            json.dump(data, outfile)
def run(ctx: protocol_api.ProtocolContext):

    # Define the STEPS of the protocol
    STEP = 0
    STEPS = {  # Dictionary with STEP activation, description, and times
        1: {'Execute': True, 'description': 'Add samples (300ul)'},
    }
    for s in STEPS:  # Create an empty wait_time
        if 'wait_time' not in STEPS[s]:
            STEPS[s]['wait_time'] = 0

    if not ctx.is_simulating():
        # Folder and file_path for log time
        folder_path = '/var/lib/jupyter/notebooks/'+run_id
        if not os.path.isdir(folder_path):
            os.mkdir(folder_path)
        file_path = folder_path + '/KA_SampleSetup_pathogen_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, h_cono, v_fondo,
                      tip_recycling = 'none'):
            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.col = 0
            self.vol_well = 0
            self.h_cono = h_cono
            self.v_cono = v_fondo
            self.unused=[]
            self.tip_recycling = tip_recycling
            self.vol_well_original = reagent_reservoir_volume / num_wells

    Samples = Reagent(name = 'Samples',
                      flow_rate_aspirate = 1,
                      flow_rate_dispense = 1,
                      rinse = False,
                      delay = 0,
                      reagent_reservoir_volume = 700 * 24,
                      num_wells = 24,  # num_cols comes from available columns
                      h_cono = 4,
                      v_fondo = 4 * math.pi * 4**3 / 3
                      )  # Sphere

    Samples.vol_well = 700

    ##################
    # Custom functions
    def generate_source_table(source):
        '''
        Concatenate the wells from the different origin racks
        '''
        for rack_number in range(len(source)):
            if rack_number == 0:
                s = source[rack_number].wells()
            else:
                s = s + source[rack_number].wells()
        return s

    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, rate = reagent.flow_rate_aspirate)  # 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 = -5))
        if touch_tip == True:
            pipet.touch_tip(speed = 20, v_offset = -5, radius = 0.9)


    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

    def calc_height(reagent, cross_section_area, aspirate_volume, min_height = 0.5):
        nonlocal ctx
        ctx.comment('Remaining volume ' + str(reagent.vol_well) +
                    '< needed volume ' + str(aspirate_volume) + '?')
        if reagent.vol_well < aspirate_volume:
            reagent.unused.append(reagent.vol_well)
            ctx.comment('Next column should be picked')
            ctx.comment('Previous to change: ' + str(reagent.col))
            # column selector position; intialize to required number
            reagent.col = reagent.col + 1
            ctx.comment(str('After change: ' + str(reagent.col)))
            reagent.vol_well = reagent.vol_well_original
            ctx.comment('New volume:' + str(reagent.vol_well))
            height = (reagent.vol_well - aspirate_volume - reagent.v_cono) / cross_section_area
                    #- reagent.h_cono
            reagent.vol_well = reagent.vol_well - aspirate_volume
            ctx.comment('Remaining volume:' + str(reagent.vol_well))
            if height < min_height:
                height = min_height
            col_change = True
        else:
            height = (reagent.vol_well - aspirate_volume - reagent.v_cono) / cross_section_area #- reagent.h_cono
            reagent.vol_well = reagent.vol_well - aspirate_volume
            ctx.comment('Calculated height is ' + str(height))
            if height < min_height:
                height = min_height
            ctx.comment('Used height is ' + str(height))
            col_change = False
        return height, col_change

    ##########
    # 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
        pip.pick_up_tip()

    ####################################
    # load labware and modules

    ####################################
    # Load Sample racks
    if NUM_SAMPLES < 96:
        rack_num = math.ceil(NUM_SAMPLES / 24)
        ctx.comment('Used source racks are ' + str(rack_num))
        samples_last_rack = NUM_SAMPLES - rack_num * 24
    else:
        rack_num = 4
    source_racks = [ctx.load_labware(
        'opentrons_24_tuberack_generic_2ml_screwcap', slot,
        'source tuberack with screwcap' + str(i + 1)) for i, slot in enumerate(['4', '1', '6', '3'][:rack_num])
    ]

    ##################################
    # Destination plate
    dest_plate = ctx.load_labware(
        'kf_96_wellplate_2400ul', '5', 'KF 96well destination plate')

    ####################################
    # Load tip_racks
    # tips20 = [ctx.load_labware('opentrons_96_filtertiprack_20ul', slot, '20µl filter tiprack')
    # for slot in ['2', '8']]
    tips1000 = [ctx.load_labware('opentrons_96_filtertiprack_1000ul', slot, '1000µl filter tiprack')
                for slot in ['7', '10']]

    ################################################################################
    # Declare which reagents are in each reservoir as well as deepwell and elution plate

    # setup samples and destinations
    sample_sources_full = generate_source_table(source_racks)
    sample_sources = sample_sources_full[:NUM_SAMPLES]
    destinations = dest_plate.wells()[:NUM_SAMPLES]

    # p20 = ctx.load_instrument(
    # 'p20_single_gen2', mount='right', tip_racks=tips20)
    p1000 = ctx.load_instrument(
        'p1000_single_gen2', 'left', tip_racks=tips1000)  # load P1000 pipette

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

    ############################################################################
    # STEP 1: Add Samples
    ############################################################################
    STEP += 1
    if STEPS[STEP]['Execute'] == True:
        ctx.comment('Step ' + str(STEP) + ': ' + STEPS[STEP]['description'])
        ctx.comment('###############################################')

        # Transfer parameters
        start = datetime.now()
        for s, d in zip(sample_sources, destinations):
            if not p1000.hw_pipette['has_tip']:
                pick_up(p1000)
            # Mix the sample BEFORE dispensing
            #custom_mix(p1000, reagent = Samples, location = s, vol = volume_sample, rounds = 2, blow_out = True, mix_height = 15)
            move_vol_multichannel(p1000, reagent = Samples, source = s, dest = d,
            vol=volume_sample, air_gap_vol = air_gap_vol, x_offset = x_offset,
                               pickup_height = 1, rinse = Samples.rinse, disp_height = -10,
                               blow_out = True, touch_tip = True)
            # Mix the sample AFTER dispensing
            #custom_mix(p1000, reagent = Samples, location = d, vol = volume_sample, rounds = 2, blow_out = True, mix_height = 15)
            # Drop tip and update counter
            p1000.drop_tip()
            tip_track['counts'][p1000] += 1

        # Time statistics
        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
    from opentrons.drivers.rpi_drivers import gpio
    for i in range(3):
        gpio.set_rail_lights(False)
        gpio.set_button_light(1, 0, 0)
        time.sleep(0.3)
        gpio.set_rail_lights(True)
        gpio.set_button_light(0, 0, 1)
        time.sleep(0.3)
    gpio.set_button_light(0, 1, 0)
    ctx.comment(
        'Finished! \nMove deepwell plate (slot 5) to Station C for MMIX addition and qPCR preparation.')
    ctx.comment('Used p1000 tips in total: ' + str(tip_track['counts'][p1000]))
    ctx.comment('Used p1000 racks in total: ' +
                str(tip_track['counts'][p1000] / 96))
Example #30
0
def run(protocol: protocol_api.ProtocolContext):
    """Function to handle the aliquoting of Illumina primers."""

    # Loading labware
    strips = protocol.load_labware('biorad_96_wellplate_200ul_pcr', 3,
                                   '96plate')
    tiprack_1 = protocol.load_labware('opentrons_96_tiprack_300ul', 9,
                                      '300tips_1')
    f_primers_1 = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap', 1,
        'Fprimers_1')
    f_primers_2 = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap', 4,
        'Fprimers_2')
    r_primers_1 = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap', 7,
        'Rprimers_1')
    r_primers_2 = protocol.load_labware(
        'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap', 10,
        'Rprimers_2')

    # Load pipette
    p300 = protocol.load_instrument('p300_single_gen2',
                                    'right',
                                    tip_racks=[tiprack_1])

    # Define functions for transferring.
    def transfer_f():
        "Transfer the forward primers to the strips."
        # Strip 1 F
        p300.transfer(20, [
            f_primers_1.columns_by_name()[column_name]
            for column_name in ['1', '2']
        ],
                      strips.columns_by_name()['1'],
                      new_tip='always')
        # Strip 2 F
        p300.transfer(20, [
            f_primers_1.columns_by_name()[column_name]
            for column_name in ['3', '4']
        ],
                      strips.columns_by_name()['4'],
                      new_tip='always')
        # Strip 3 F
        p300.transfer(20, [
            f_primers_1.columns_by_name()[column_name]
            for column_name in ['5', '6']
        ],
                      strips.columns_by_name()['7'],
                      new_tip='always')
        # Strip 4 F
        p300.transfer(20, [
            f_primers_2.columns_by_name()[column_name]
            for column_name in ['1', '2']
        ],
                      strips.columns_by_name()['10'],
                      new_tip='always')

    def transfer_r():
        "Transfer the reverse primers to the strips."
        # Strip 1 R
        p300.transfer(20, [
            r_primers_1.columns_by_name()[column_name]
            for column_name in ['1', '2']
        ],
                      strips.columns_by_name()['1'],
                      new_tip='always')
        # Strip 2 R
        p300.transfer(20, [
            r_primers_1.columns_by_name()[column_name]
            for column_name in ['3', '4']
        ],
                      strips.columns_by_name()['4'],
                      new_tip='always')
        # Strip 3 R
        p300.transfer(20, [
            r_primers_1.columns_by_name()[column_name]
            for column_name in ['5', '6']
        ],
                      strips.columns_by_name()['7'],
                      new_tip='always')
        # Strip 4 R
        p300.transfer(20, [
            r_primers_2.columns_by_name()[column_name]
            for column_name in ['1', '2']
        ],
                      strips.columns_by_name()['10'],
                      new_tip='always')

    # Numbers of forward primers are used because reverse primers differ per
    # aliquot.

    # 1 to 63
    transfer_f()
    transfer_r()
    protocol.pause('Change the tubes and strips.')

    # 65 to 127
    transfer_f()
    transfer_r()
    protocol.pause('Change the tubes and strips.')

    # 129 to 191
    transfer_f()
    transfer_r()
    protocol.pause('Change the tubes and strips.')

    # 193 to 255
    transfer_f()
    transfer_r()
    protocol.pause('Change the tubes and strips.')