def pick_colonies(): parser = argparse.ArgumentParser( description="Resuspend a plate of DNA on an Opentrons OT-1 robot.") parser.add_argument( '-r', '--run', required=False, action="store_true", help="Send commands to the robot and print command output.") parser.add_argument( '-i', '--inoculate', required=False, action="store_true", help="Picks colonies and inoculates a deep well plate.") parser.add_argument('-c', '--check', required=False, action="store_true", help="Allows the user to choose the colonies.") args = parser.parse_args() if args.run: port = os.environ["ROBOT_DEV"] print("Connecting robot to port {}".format(port)) robot.connect(port) else: print("Simulating protcol run") robot.connect() robot.home() p200_tipracks = [] p10_tip_racks = [] p10s_tipracks = [ containers.load('tiprack-10ul', 'E1'), containers.load('tiprack-10ul', 'E2') ] trash = containers.load('point', 'D1', 'holywastedplasticbatman') deep_well = containers.load('96-deep-well', 'C2') trans_plate = containers.load('point', 'B2') p10, p10s, p200 = ot.initialize_pipettes(p10_tipracks, p10s_tipracks, p200_tipracks, trash) assemblies = [] print("Choose which build you would like to pick from:") for index, assembly in enumerate( session.query(Plate).join(Build, Plate.builds).filter( Plate.plated == 'not_plated').order_by(Build.build_name)): print("{}. {}".format(index, assembly.builds.build_name)) assemblies.append(assembly) plate_num = int(input("Enter plate here: ")) target_plate = assemblies[plate_num] build_name = target_plate.builds.build_name path = '{}/builds/{}/{}_trans_pics'.format(BASE_PATH, build_name, build_name) for file in sorted(glob.glob('{}/*.jpg'.format(path)), reverse=True): print("Current image: ", file) skip = input('Skip? (y/n): ') if skip == 'y': continue print("Inoculate: ", args.inoculate) input() centers, agar, x_dim, y_dim, missing = find_colony_coordinates( file, args.check) coords = ot_coords(centers, agar, x_dim, y_dim) run_ot(p10s, trans_plate, deep_well, agar, coords, centers, args.inoculate) print('The following wells were skipped:\n', missing) print("Complete") robot.home() cv2.destroyAllWindows()
def plate(session,engine): ot.print_center("============ Beginning to plate ============") # Take in command line arguments parser = argparse.ArgumentParser(description="Resuspend a plate of DNA on an Opentrons OT-1 robot.") parser.add_argument('-r', '--run', required=False, action="store_true", help="Send commands to the robot and print command output.") parser.add_argument('-m', '--manual', required=False, action="store_true", help="Maunal entry of parameters.") args = parser.parse_args() # Verify that the correct robot is being used if args.run: ot.check_robot() assemblies = [] print("Choose which plate you would like to plate:") for index,assembly in enumerate(session.query(Plate).join(Build,Plate.builds)\ .filter(Build.status == 'building').filter(Plate.transformed == 'transformed')\ .filter(Plate.plated != 'plated').order_by(Build.build_name)): print("{}. {}".format(index,assembly.builds.build_name)) assemblies.append(assembly) plate_num = ot.request_info("Enter plate here: ",type='int') target_plate = assemblies[plate_num] build_map = target_plate.wells if len(target_plate.wells) > 48: print("Too many samples to plate at once") portion = int(ot.request_info("Choose which half to plate, 1 or 2: ",type='int')) if portion == 1: build_map = target_plate.wells[:48] else: build_map = target_plate.wells[48:] num_reactions = len(build_map) else: portion = 1 num_reactions = len(build_map) num_rows = math.ceil(num_reactions / 8) print("num rows: ",num_rows) trans_per_plate = 3 num_plates = num_rows // trans_per_plate agar_plate_names = [] for plate_num in range(num_plates): if portion == 2: plate_num += 2 current_plate = target_plate.builds.build_name + "_p" + str(plate_num + 1) agar_plate_names.append(current_plate) print(agar_plate_names) print("You will need {} agar plates".format(len(agar_plate_names))) ## ============================================= ## SETUP THE OT-1 DECK ## ============================================= # Allocate slots for the required agar plates AGAR_SLOTS = ['D2','D3'] layout = list(zip(agar_plate_names,AGAR_SLOTS[:len(agar_plate_names)])) print(layout) # Specify the locations of each object on the deck locations = { "tiprack-200" : "A3", "tiprack-10_2" : "E3", "tiprack-10_3" : "E2", "tiprack-10_1" : "E1", "trash" : "D1", "PCR-strip-tall" : "C3", "Transformation" : "C2", "Tube_rack" : "B1" } locations.update(dict(layout)) ot.print_layout(locations) ## Initialize the OT-1 ## ============================================ # Determine whether to simulate or run the protocol if args.run: port = os.environ["ROBOT_DEV"] print("Connecting robot to port {}".format(port)) robot.connect(port) else: print("Simulating protcol run") robot.connect() # Start timer start = datetime.now() print("Starting run at: ",start) # Start up and declare components on the deck robot.home() p200_tipracks = [ containers.load('tiprack-200ul', locations['tiprack-200']), ] p10_tipracks = [ containers.load('tiprack-10ul', locations['tiprack-10_2']), containers.load('tiprack-10ul', locations['tiprack-10_3']), containers.load('tiprack-10ul', locations['tiprack-10_1']) ] p10s_tipracks = [ ] transformation_plate = containers.load('96-PCR-tall', locations['Transformation']) trash = containers.load('point', locations['trash'], 'holywastedplasticbatman') centrifuge_tube = containers.load('tube-rack-2ml',locations['Tube_rack']) master = containers.load('PCR-strip-tall', locations['PCR-strip-tall']) agar_plates = {} for plate, slot in layout: agar_plates[plate] = containers.load('96-deep-well', slot) print("agar_plates", agar_plates[plate]) print("agar_plates",agar_plates,"\n") p10,p10s,p200 = ot.initialize_pipettes(p10_tipracks,p10s_tipracks,p200_tipracks,trash) def agar_plating(pipette,row,volume,calibrate,z): ''' Dispenses the cells to be plated prior to reaching the agar and then stabs the tips slightly into the agar such that the droplets that pull up on the side of the tips make contact with the agar ''' pipette.dispense(volume-1,row.top()) pipette.dispense(1,row.bottom()) if calibrate: calibrate,z = ot.change_height(p10,agar_plates[plate],agar_plates[plate].rows(plating_row)[0],recalibrate=True) return calibrate,z num_dilutions = 4 plate_vol = 7.5 dilution_vol = 9 waste_vol = 2.5 plating_row = 0 calibrate = True z = 0 media_per_tube = 150 plate = agar_plate_names[0] plate_counter = 0 # Aliquot the LB into the PCR tube strip for the dilutions p200.pick_up_tip() for well in range(8): print("Transferring {}ul to tube {}".format(media_per_tube,well)) p200.transfer(media_per_tube, centrifuge_tube['A1'].bottom(),master.wells(well).bottom(),new_tip='never') p200.drop_tip() #input("Start the other run") # Iterate through each row of the transformation plate for trans_row in range(num_rows): # Iterates through each dilution for dilution in range(num_dilutions): # Resets to switch to the next plate if plating_row == 12: p200.pick_up_tip() for well in range(8): print("Transferring {}ul to tube {}".format(media_per_tube,well)) p200.transfer(media_per_tube, centrifuge_tube['B1'].bottom(),master.wells(well).bottom(),new_tip='never') p200.drop_tip() plate = agar_plate_names[1] print("changing to :", plate) plating_row = 0 calibrate = True print("trans_row",trans_row, "dilution",dilution,"plate",plate,"plate row",plating_row) p10.pick_up_tip() print("Diluting cells in row {} with {}ul".format(trans_row, dilution_vol)) p10.transfer(dilution_vol, master['A1'].bottom(), transformation_plate.rows(trans_row).bottom(),new_tip='never',mix_before=(1,9)) print("Plating {}ul from transformation row {} onto {} in row {}".format(plate_vol,trans_row,plate,plating_row)) p10.aspirate(plate_vol,transformation_plate.rows(trans_row).bottom()) calibrate,z = agar_plating(p10,agar_plates[plate].rows(plating_row),plate_vol,calibrate,z) print("Discard {}ul from transformation row {} into waste tube".format(waste_vol,trans_row)) p10.aspirate(waste_vol,transformation_plate.rows(trans_row).bottom()) p10.drop_tip() plating_row += 1 stop = datetime.now() print(stop) runtime = stop - start print("Total runtime is: ", runtime) print("Rehoming") robot.home() commit = ot.request_info("Commit changes? (y/n): ",type='string',select_from=['y','n']) if commit == 'y': if len(target_plate.wells) <= 48: target_plate.plated = 'plated' else: ans = ot.request_info('Plated both halves of the build? (y/n): ',type='string',select_from=['y','n']) if ans == 'y': target_plate.plated = 'plated' session.commit() return
return sub_location layout = pd.read_csv('./all_deck_layout.csv') layout['type'] = layout.container_type.apply(lambda x: 0 if 'tiprack' in x else 1) sections = layout.groupby(['pipette', 'type']) for (pip, type), data in sections: data = data.reset_index() for i, row in data.iterrows(): input('Make sure {} is in slot {}'.format(row['container_type'], row['slot'])) current_container = containers.load(row['container_type'], row['slot']) p10, p10s, p200 = ot.initialize_pipettes(p10_tipracks, p10s_tipracks, p200_tipracks, trash) pipette_dict = {'p10': p10, 'p10s': p10s, 'p200': p200} pipette = pipette_dict[row['pipette']] sub_location = check_calibration(robot, pipette, current_container) if type == 0: print('Tipracks', len(data)) if i == len(data) - 1: print('Last rack') last_rack = sub_location else: pipette.drop_tip(sub_location) print('On to next rack') elif type == 1: if i == len(data) - 1:
def transform(session, engine): # Take in command line arguments parser = argparse.ArgumentParser( description="Resuspend a plate of DNA on an Opentrons OT-1 robot.") parser.add_argument( '-r', '--run', required=False, action="store_true", help="Send commands to the robot and print command output.") # parser.add_argument('-m', '--manual', required=False, action="store_true", help="Maunal entry of parameters.") args = parser.parse_args() assemblies = [] print("Choose which plate you would like to transform:") for index, assembly in enumerate( session.query(Plate).join( Build, Plate.builds).filter(Build.status == 'building').filter( Plate.transformed == 'not_transformed').order_by( Build.build_name)): print("{}. {}".format(index, assembly.builds.build_name)) assemblies.append(assembly) plate_num = int(ot.request_info("Enter plate here: ", type='int')) target_plate = assemblies[plate_num] num_reactions = len(target_plate.wells) num_rows = num_reactions // 8 # Verify that the correct robot is being used if args.run: ot.check_robot() # Specify the locations of each object on the deck locations = { "tiprack-200": "A3", "tiprack-10_2": "E2", "tiprack-10_3": "E3", "tiprack-10_1": "E1", "trash": "D1", "Transformation": "C2", "Build_plate": "C3", "Tube_rack": "B1" } ot.print_layout(locations) ## Initialize the OT-1 ## ============================================ # Determine whether to simulate or run the protocol if args.run: port = os.environ["ROBOT_DEV"] print("Connecting robot to port {}".format(port)) robot.connect(port) else: print("Simulating protcol run") robot.connect() # Start timer start = datetime.now() print("Starting run at: ", start) # Start up and declare components on the deck robot.home() p200_tipracks = [ containers.load('tiprack-200ul', locations['tiprack-200']), ] p10_tipracks = [ containers.load('tiprack-10ul', locations['tiprack-10_2']), containers.load('tiprack-10ul', locations['tiprack-10_1']), ] p10s_tipracks = [ containers.load('tiprack-10ul', locations["tiprack-10_3"]) ] transformation_plate = containers.load('96-PCR-tall', locations['Transformation']) trash = containers.load('point', locations['trash'], 'holywastedplasticbatman') centrifuge_tube = containers.load('tube-rack-2ml', locations['Tube_rack']) build_plate = containers.load('96-PCR-tall', locations['Build_plate']) p10, p10s, p200 = ot.initialize_pipettes(p10_tipracks, p10s_tipracks, p200_tipracks, trash) dna_vol = 2 for row in range(num_rows): p10.pick_up_tip() p10.transfer(dna_vol, build_plate.rows(row).bottom(), transformation_plate.rows(row).bottom(), new_tip='never', mix_before=(2, 9), blow_out=True) print('Transferring DNA from row {}'.format(row)) p10.drop_tip() if num_reactions % 8 > 0: p10s.pick_up_tip() print("need single channel for {}".format(num_reactions % 8)) for missing in range(num_reactions % 8): current_well = (8 * num_rows) + (missing) print("Transferring {}ul of DNA to {}".format( dna_vol, current_well)) p10s.transfer(dna_vol, build_plate.wells(current_well).bottom(), transformation_plate.wells(current_well).bottom(), blow_out=True, mix_before=(1, 8), new_tip='never') p10s.drop_tip() commit = ot.request_info("Commit changes? (y/n): ", type='string', select_from=['y', 'n']) if commit == 'y': target_plate.transformed = 'transformed' session.commit() else: print('Not committed')
def resuspension(session, engine, target): ot.print_center("============ Beginning resuspension ============") # Initial Setup fmoles = 40 # Load files parser = argparse.ArgumentParser( description="Resuspend a plate of DNA on an Opentrons OT-1 robot.") parser.add_argument( '-r', '--run', required=False, action="store_true", help="Send commands to the robot and print command output.") args = parser.parse_args() # Verify that the correct robot is being used if args.run: ot.check_robot() ## ============================================= ## SETUP THE OT-1 DECK ## ============================================= # Specify the locations of each object on the deck locations = { "tiprack-200": "A3", "tiprack-10": "E2", "tiprack-10s1": "E3", "tiprack-10s2": "E1", "trash": "D1", "PLATE HERE": "B2", "Trough": "B1" } ot.print_layout(locations) ot.print_center('...Calculating the volumes to resuspend with...') def calc_vol(amount, length, fmoles=40): return math.ceil( ((((amount * 1000) / (660 * length)) * 1000) / fmoles) * 2), fmoles total = 0 for well in target.wells: length = len(well.fragments.seq) amount = well.syn_yield volume, conc = calc_vol(amount, length) well.volume = volume well.concentration = conc total += volume session.add(well) # print("total volume of water needed: {}uL".format(total)) # num_tubes = math.ceil(total / 1000) # print("Prep {} tubes with 1.2mL".format(num_tubes)) # input("Press Enter when you have added them to the tube rack") ## Initialize the OT-1 # Determine whether to simulate or run the protocol if args.run: #port = robot.get_serial_ports_list()[0] port = os.environ["ROBOT_DEV"] print("Connecting robot to port {}".format(port)) robot.connect(port) else: print("Simulating protcol run") robot.connect() start = datetime.now() print("Starting run at: ", start) # Start up and declare components on the deck robot.home() p200_tipracks = [ containers.load('tiprack-200ul', locations["tiprack-200"]), ] p10_tipracks = [ containers.load('tiprack-10ul', locations["tiprack-10"]), ] p10s_tipracks = [ containers.load('tiprack-10ul', locations["tiprack-10s1"]), containers.load('tiprack-10ul', locations["tiprack-10s2"]) ] trash = containers.load('point', locations["trash"], 'holywastedplasticbatman') centrifuge_tube = containers.load('trough-12row', locations["Trough"]) # centrifuge_tube = containers.load('tube-rack-2ml',locations["Tube_rack"]) resuspend_plate = containers.load('96-flat', locations["PLATE HERE"]) p10, p10s, p200 = ot.initialize_pipettes(p10_tipracks, p10s_tipracks, p200_tipracks, trash) ## ============================================= ## OT-1 PROTOCOL ## ============================================= # Start timer start = datetime.now() print("Starting run at: ", start) tubes = dict({ 1: "A1", 2: "B1", 3: "C1", 4: "D1", 5: "A2", 6: "B2", 7: "C2", 8: "D2", 9: "A3", 10: "B3", 11: "C3", 12: "D3", 13: "A4", 14: "B4", 15: "C4" }) tube_count = 1 current_vol = 1200 last_pipette = "neither" exclude_wells = [] for target_well in target.wells: vol = target_well.volume well = target_well.address if well in exclude_wells: continue # Determine which pipette to use if vol < 20: # Makes sure that the robot doesn't pick up multiple sets of tips if last_pipette == "p200": print("Changing to p10s") p200.drop_tip() p10s.pick_up_tip() elif last_pipette == "neither": p10s.pick_up_tip() # Changes tubes of water when one gets low # if current_vol - vol < 200: # tube_count += 1 # current_vol = 1200 # current_vol -= vol print("Adding {}ul to well {} with the p10".format(vol, well)) #p10s.transfer(vol, centrifuge_tube[tubes[tube_count]].bottom(), resuspend_plate.wells(well),touch_tip=True, blow_out=True, new_tip='never') p10s.transfer(vol, centrifuge_tube['A1'], resuspend_plate.wells(well), touch_tip=True, blow_out=True, new_tip='never') # print("Currently {}ul in tube {}".format(current_vol,tubes[tube_count])) last_pipette = "p10s" else: if last_pipette == "p10s": print("Changing to p200") p10s.drop_tip() p200.pick_up_tip() elif last_pipette == "neither": p200.pick_up_tip() # Changes tubes of water when one gets low # if current_vol - vol < 100: # tube_count += 1 # current_vol = 1200 # current_vol -= vol print("Adding {}ul to well {} with the p200".format(vol, well)) #p200.transfer(vol, centrifuge_tube[tubes[tube_count]].bottom(), resuspend_plate.wells(well),touch_tip=True, blow_out=True, new_tip='never') p200.transfer(vol, centrifuge_tube['A1'], resuspend_plate.wells(well), touch_tip=True, blow_out=True, new_tip='never') # print("currently {}ul in tube {}".format(current_vol,tubes[tube_count])) last_pipette = "p200" # Last drop tip if last_pipette == "p10s": p10s.drop_tip() elif last_pipette == "p200": p200.drop_tip() stop = datetime.now() print(stop) runtime = stop - start print("Total runtime is: ", runtime) robot.home() target.resuspend() session.add(target) commit = int(ot.request_info("Commit changes (1-yes, 2-no): ", type='int')) if commit == 1: session.commit() ot.print_center('...Completed resuspension...') return
def run_build(session, engine): ot.print_center("============ Beginning build ============") # Take in the 'run' argument from the command line parser = argparse.ArgumentParser( description="Resuspend a plate of DNA on an Opentrons OT-1 robot.") parser.add_argument( '-r', '--run', required=False, action="store_true", help="Send commands to the robot and print command output.") args = parser.parse_args() # Verify that the correct robot is being used if args.run: ot.check_robot() # Choose which build plan to build build_options = [] builds = [ build for build in session.query(Build).filter(Build.status == 'planning') ] if len(builds) == 0: sys.exit( 'No plans available, run `create_build_plan.py` to generate them') for num, build in enumerate([ build for build in session.query(Build).filter( Build.status == 'planning') ]): print('{} - {}'.format(num, build.build_name)) build_options.append(build) ans = ot.request_info("Enter desired plan number: ", type='int') target_build = build_options[ans] # Use that build name to create a dataframe with the information from the plan query = "SELECT parts.part_id,builds.build_name,part_wells.address as destination,fragments.fragment_name,frag_plates.plate_name,frag_plates.plate_id,frag_wells.address as source,frag_wells.volume FROM parts \ INNER JOIN wells AS part_wells ON parts.id = part_wells.part_id\ INNER JOIN plates AS part_plates ON part_wells.plate_id = part_plates.id\ INNER JOIN builds ON part_plates.build_id = builds.id\ INNER JOIN part_frag ON parts.id = part_frag.part_id\ INNER JOIN fragments ON part_frag.fragment_id = fragments.id\ INNER JOIN wells AS frag_wells ON fragments.id = frag_wells.fragment_id\ INNER JOIN plates AS frag_plates ON frag_wells.plate_id = frag_plates.id\ WHERE builds.build_name = '{}'".format(target_build.build_name) build_plan = pd.read_sql_query(query, con=engine) print(build_plan) frags = build_plan.groupby('part_id').agg(len) if len(frags) == len( [frag for frag in frags.fragment_name.tolist() if frag == 2]): print('Build only contains 2 fragment assemblies') num_frags = 2 rxn_vol = 0.6 else: print('Using MM for single fragment') rxn_vol = 0.8 num_frags = 1 unique_plates = build_plan.plate_id.unique().tolist() # Give each row a rank based on the order of the plates to sort on later plate_dict = dict([[y, x] for x, y in enumerate(unique_plates)]) build_plan['plate_rank'] = build_plan.plate_id.apply( lambda x: plate_dict[x]) build_plan = build_plan.sort_values('plate_rank') # Currently available spots on the OT-one deck SOURCE_SLOTS = ['D2', 'D3', 'B2'] ## Generate a list of unique plates that are needed plate_index = [(y, x) for x, y in enumerate(unique_plates)] plate_index = dict(plate_index) ## Group the plates so that they can be swapped in batches ot.print_center("...Grouping plates...") group_plates = [ unique_plates[n:n + len(SOURCE_SLOTS)] for n in range(0, len(unique_plates), len(SOURCE_SLOTS)) ] for num, group in enumerate(group_plates): print("Group{}: {}".format(num + 1, group)) ot.print_center("...Checking if plates need to be resuspended...") query_resuspend = "SELECT plates.plate_id,plates.resuspended FROM plates\ WHERE plates.resuspended = 'not_resuspended'\ AND plates.plate_id IN ({})".format( ot.list_to_string(unique_plates)) resuspended = pd.read_sql_query(query_resuspend, con=engine) if len(resuspended) == 0: print('All plates are resuspended') else: for i, plate in resuspended.iterrows(): ans = ot.request_info( 'Plate {} is not resuspended, would you like to resuspend it? y/n: ' .format(plate['plate_id']), type='string') if ans == 'y': resuspend.resuspension( session, engine, session.query(Plate).filter( Plate.plate_id == plate['plate_id']).one()) query = "SELECT parts.part_id,builds.build_name,part_wells.address as destination,fragments.fragment_name,frag_plates.plate_name,frag_plates.plate_id,frag_wells.address as source,frag_wells.volume FROM parts \ INNER JOIN wells AS part_wells ON parts.id = part_wells.part_id\ INNER JOIN plates AS part_plates ON part_wells.plate_id = part_plates.id\ INNER JOIN builds ON part_plates.build_id = builds.id\ INNER JOIN part_frag ON parts.id = part_frag.part_id\ INNER JOIN fragments ON part_frag.fragment_id = fragments.id\ INNER JOIN wells AS frag_wells ON fragments.id = frag_wells.fragment_id\ INNER JOIN plates AS frag_plates ON frag_wells.plate_id = frag_plates.id\ WHERE builds.build_name = '{}'".format(target_build.build_name) build_plan = pd.read_sql_query(query, con=engine) build_plan['plate_rank'] = build_plan.plate_id.apply( lambda x: plate_dict[x]) build_plan = build_plan.sort_values('plate_rank') input("Press enter to continue") ## ============================================= ## SETUP THE OT-1 DECK ## ============================================= # Specify the locations of each object on the deck locations = { "tiprack-200": "A3", "tiprack-10": "E1", "tiprack-10s1": "E3", "tiprack-10s2": "E2", "trash": "D1", "PCR-strip-tall": "C3", "DEST_PLATE": "C2", "Tube_rack": "B1" } # Sets the first group of plates used_plates = [] plate_counter = 0 current_group = group_plates[plate_counter] source_plates = ot.change_plates(locations, current_group, SOURCE_SLOTS) ## ============================================= ## SETUP THE MASTER MIX ## ============================================= vol = int( ot.request_info('Enter desired reaction volume (i.e. 5,10,20): ', type='int')) # Set the proportion of master mix to fragment to 4:1 master_volume = rxn_vol * vol frag_vol = 0.2 * vol ot.print_center('...Calculating master mix volumes...') # Set a multiplier to account for pipetting error and evaporation extra_master = 1.3 unique_frag = build_plan[['part_id', 'fragment_name', 'destination']].drop_duplicates() frag_df = unique_frag.groupby('destination').agg(len).part_id frag_df = frag_df.reset_index() frag_df = frag_df.rename(columns={'part_id': 'frag_num'}) frag_dict = dict( zip(frag_df.destination.tolist(), frag_df.frag_num.tolist())) build_plan['frag_num'] = build_plan.destination.apply( lambda x: frag_dict[x]) unique_df = build_plan[['part_id', 'destination', 'frag_num']].drop_duplicates() total_rxns = unique_df.frag_num.sum() need_extra = unique_df[unique_df.frag_num > 1] num_wells = len(build_plan.part_id.unique().tolist()) num_rows = num_wells // 8 master_reactions = math.ceil((total_rxns) * extra_master) print("Total rxns: {}".format(total_rxns, master_reactions)) # Generate the dataframe to present the master mix composition master_mix = ot.make_gg_rxns(master_reactions, master_volume) print("Use the table below to create the master mix") print() print(master_mix) print() print("Place the master mix in the 'A1' position of the tube rack") print("Also place a tube of with 1.2 mL of water in the 'B1' position ") input("Press enter to continue") ## ============================================= ## INITIALIZE THE OT-1 ## ============================================= # Determine whether to simulate or run the protocol if args.run: port = os.environ["ROBOT_DEV"] print("Connecting robot to port {}".format(port)) robot.connect(port) else: print("Simulating protcol run") robot.connect() # Declare components on the deck p200_tipracks = [ containers.load('tiprack-200ul', locations["tiprack-200"]), ] p10_tipracks = [ containers.load('tiprack-10ul', locations["tiprack-10"]), ] p10s_tipracks = [ containers.load('tiprack-10ul', locations["tiprack-10s1"]), containers.load('tiprack-10ul', locations["tiprack-10s2"]) ] trash = containers.load('point', locations["trash"], 'holywastedplasticbatman') centrifuge_tube = containers.load('tube-rack-2ml', locations["Tube_rack"]) master = containers.load('PCR-strip-tall', locations["PCR-strip-tall"]) dest_plate = containers.load('96-PCR-tall', locations["DEST_PLATE"]) p10, p10s, p200 = ot.initialize_pipettes(p10_tipracks, p10s_tipracks, p200_tipracks, trash) # Update database status def exit_handler(): print('Choose one of the following options:') print('1-Save successful assembly\n2-Restore plan\n3-Abandon plan') ans = ot.request_info('Select what to do: ', type='int', select_from=[1, 2, 3]) if ans == 1: ot.print_center('...Assembly is complete...') elif ans == 2: target_build.status = 'planning' ot.print_center('...Restoring the build plan...') for part in session.query(Part).filter( Part.part_id.in_(build_plan.part_id.unique().tolist())): part.change_status('planning') elif ans == 3: target_build.status = 'abandoned' ot.print_center('...Unstaging all parts in build plan...') for part in session.query(Part).filter( Part.part_id.in_(build_plan.part_id.unique().tolist())): part.change_status('received') session.commit() target_build.status = 'building' session.commit() atexit.register(exit_handler) ## ============================================= ## OT-1 PROTOCOL ## ============================================= # Start timer start = datetime.now() print("Starting run at: ", start) # Home the robot to start robot.home() # Aliquot the master mix into the PCR tube strip vol_per_tube = round((num_rows * master_volume * extra_master), 2) print("Aliquoting MM into PCR tubes") print("{}ul into each tube".format(vol_per_tube)) p200.pick_up_tip() for well in range(8): print("Transferring {}ul to well {}".format(vol_per_tube, well)) p200.transfer(vol_per_tube, centrifuge_tube['A1'].bottom(), master.wells(well).bottom(), mix_before=(3, 50), new_tip='never') p200.drop_tip() # Aliquot the master mix into all of the desired wells p10.pick_up_tip() for row in range(num_rows): print("Transferring {}ul of master mix to row {}".format( master_volume, int(row) + 1)) p10.transfer(master_volume, master['A1'].bottom(), dest_plate.rows(row).bottom(), mix_before=(1, 8), blow_out=True, new_tip='never') p10.drop_tip() # Aliquot master mix into the last row if not a complete row if num_wells % 8 > 0: p10s.pick_up_tip() print("need single channel for {}".format(num_wells % 8)) for missing in range(num_wells % 8): current_well = (8 * num_rows) + (missing) print("Transferring {}ul of extra MM to {}".format( master_volume, current_well)) p10s.transfer(master_volume, centrifuge_tube['A1'].bottom(), dest_plate.wells(current_well).bottom(), blow_out=True, mix_before=(1, 8), new_tip='never') p10s.drop_tip() # Aliquot extra master mix into wells with multiple fragments if len(need_extra) != 0: p10s.pick_up_tip() for i, transfer in need_extra.iterrows(): extra_volume = (int(transfer['frag_num']) - 1) * master_volume current_well = transfer['destination'] print("Transferring {}ul of extra MM to {}".format( extra_volume, current_well)) p10s.transfer(extra_volume, centrifuge_tube['A1'].bottom(), dest_plate.wells(current_well).bottom(), blow_out=True, mix_before=(1, 8), new_tip='never') p10s.drop_tip() else: print('No extra MM must be aliquoted') ## Add the fragments from the source plates to the destination plate ## ============================================ # Sets the volume of water to dilute with, if needed dil_vol = 5 build_plan = build_plan.sort_values('plate_rank') for i, row in build_plan.iterrows(): start_well = row['source'] dest_well = row['destination'] gene = row['part_id'] plate = row['plate_id'] volume = row['volume'] if plate not in current_group: plate_counter += 1 current_group = group_plates[plate_counter] source_plates = ot.change_plates(locations, current_group, SOURCE_SLOTS) p10s.pick_up_tip() # Only dilutes wells that have low starting volume if volume < 30: print("Diluting sample in plate {} well {} with {}uL of water". format(plate, start_well, dil_vol)) p10s.transfer(dil_vol, centrifuge_tube['B1'].bottom(), source_plates[plate].wells(start_well).bottom(), new_tip='never') print("Transferring {} of {} from plate {} well {} to well {}".format( frag_vol, gene, plate, start_well, dest_well)) p10s.mix(3, 8, source_plates[plate].wells(start_well).bottom()) # Checks the calibration to make sure that it can aspirate correctly p10s.aspirate(frag_vol, source_plates[plate].wells(start_well).bottom()) # if plate not in used_plates: # ot.change_height(p10s,source_plates[plate],source_plates[plate].wells(start_well)) p10s.dispense(frag_vol, dest_plate.wells(dest_well).bottom()) used_plates.append(plate) p10s.drop_tip() robot.home() ot.print_center('...Updating part status...') to_build = [well.parts for well in target_build.plates[0].wells] for part in to_build: part.change_status('building') session.commit() return