From cde88cbc35700de1beeffe7b6ed961d6a6ae2ed3 Mon Sep 17 00:00:00 2001 From: rclarke0 Date: Tue, 23 Jul 2024 17:27:33 -0400 Subject: [PATCH 01/13] increase google sheet columns --- abr-testing/abr_testing/automation/google_sheets_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abr-testing/abr_testing/automation/google_sheets_tool.py b/abr-testing/abr_testing/automation/google_sheets_tool.py index 3a6590fa03b..78cbc17abf6 100644 --- a/abr-testing/abr_testing/automation/google_sheets_tool.py +++ b/abr-testing/abr_testing/automation/google_sheets_tool.py @@ -57,7 +57,7 @@ def open_worksheet(self, tab_number: int) -> Any: def create_worksheet(self, title: str) -> Optional[str]: """Create a worksheet with tab name. Existing spreadsheet needed.""" try: - new_sheet = self.spread_sheet.add_worksheet(title, rows="2500", cols="40") + new_sheet = self.spread_sheet.add_worksheet(title, rows="2500", cols="50") return new_sheet.id except gspread.exceptions.APIError: print("Sheet already exists.") From 8f2c3ee9b24226e5314e098407a4c0bb9d398bd9 Mon Sep 17 00:00:00 2001 From: rclarke0 Date: Fri, 25 Oct 2024 11:31:54 -0400 Subject: [PATCH 02/13] liquid fill protocls --- .../protocol_simulation/abr_sim_check.py | 2 +- ...moBIOMICS_Magbead_DNA_Cells_Flex_220api.py | 733 ++++++++++++++++++ abr-testing/abr_testing/protocols/helpers.py | 19 + .../10_ZymoBIOMICS Magbead Liquid Setup.py | 59 ++ .../11_Dynabeads RIT Liquid Setup.py | 57 ++ ...APA HyperPlus Library Prep Liquid Setup.py | 79 ++ .../1_Simple normalize long Liquid Setup.py | 35 + .../2_BMS_PCR_protocol Liquid Setup.py | 33 + .../4_Illumina DNA Enrichment Liquid Setup.py | 87 +++ .../5_96ch Complex Protocol Liquid Setup.py | 49 ++ ...DQ DNA Bacteria Extraction Liquid Setup.py | 70 ++ ...ermo MagMax RNA Extraction Liquid Setup.py | 106 +++ abr-testing/test_debug | 0 13 files changed, 1328 insertions(+), 1 deletion(-) create mode 100644 abr-testing/abr_testing/protocols/api 2.20/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex_220api.py create mode 100644 abr-testing/abr_testing/protocols/helpers.py create mode 100644 abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py create mode 100644 abr-testing/abr_testing/protocols/liquid_setups/11_Dynabeads RIT Liquid Setup.py create mode 100644 abr-testing/abr_testing/protocols/liquid_setups/12_KAPA HyperPlus Library Prep Liquid Setup.py create mode 100644 abr-testing/abr_testing/protocols/liquid_setups/1_Simple normalize long Liquid Setup.py create mode 100644 abr-testing/abr_testing/protocols/liquid_setups/2_BMS_PCR_protocol Liquid Setup.py create mode 100644 abr-testing/abr_testing/protocols/liquid_setups/4_Illumina DNA Enrichment Liquid Setup.py create mode 100644 abr-testing/abr_testing/protocols/liquid_setups/5_96ch Complex Protocol Liquid Setup.py create mode 100644 abr-testing/abr_testing/protocols/liquid_setups/7_HDQ DNA Bacteria Extraction Liquid Setup.py create mode 100644 abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py create mode 100644 abr-testing/test_debug diff --git a/abr-testing/abr_testing/protocol_simulation/abr_sim_check.py b/abr-testing/abr_testing/protocol_simulation/abr_sim_check.py index 513860baa9b..4d2b6dcd18a 100644 --- a/abr-testing/abr_testing/protocol_simulation/abr_sim_check.py +++ b/abr-testing/abr_testing/protocol_simulation/abr_sim_check.py @@ -21,7 +21,7 @@ def run(file_to_simulate: str) -> None: exclude = [ "__init__.py", - "shared_vars_and_funcs.py", + "helpers.py", ] # Walk through the root directory and its subdirectories for root, dirs, files in os.walk(root_dir): diff --git a/abr-testing/abr_testing/protocols/api 2.20/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex_220api.py b/abr-testing/abr_testing/protocols/api 2.20/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex_220api.py new file mode 100644 index 00000000000..3ef8d3bbae0 --- /dev/null +++ b/abr-testing/abr_testing/protocols/api 2.20/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex_220api.py @@ -0,0 +1,733 @@ +"""Flex ZymoBIOMICS Magbead DNA Extraction: Cells.""" +import math +from opentrons import types +from typing import List, Union +from opentrons import protocol_api +from opentrons.protocol_api import Well +import numpy as np +from opentrons.protocol_api.module_contexts import ( + HeaterShakerContext, + TemperatureModuleContext, +) + +metadata = { + "author": "Zach Galluzzo ", + "protocolName": "Flex ZymoBIOMICS Magbead DNA Extraction: Cells", +} + +requirements = {"robotType": "OT-3", "apiLevel": "2.20"} +""" +Slot A1: Tips 1000 +Slot A2: Tips 1000 +Slot A3: Temperature module (gen2) with 96 well PCR block and Armadillo 96 well PCR Plate +Slot B1: Tips 1000 +Slot B3: Nest 1 Well Reservoir +Slot C1: Magblock +Slot C2: Nest 12 well 15 ml Reservoir +Slot D1: H-S with Nest 96 Well Deepwell and DW Adapter +Slot D2: Nest 12 well 15 ml Reservoir +Slot D3: Trash + +Reservoir 1: +Well 1 - 12,320 ul +Wells 2-4 - 11,875 ul +Wells 5-6 - 13,500 ul +Wells 7-8 - 13,500 ul +Well 12 - 5,200 ul + +Reservoir 2: +Wells 1-12 - 9,000 ul + +""" +whichwash = 1 +sample_max = 48 +tip1k = 0 +tip200 = 0 +drop_count = 0 + + +def add_parameters(parameters: protocol_api.ParameterContext) -> None: + """Define parameters.""" + parameters.add_int( + variable_name="heater_shaker_speed", + display_name="Heater Shaker Shake Speed", + description="Speed to set the heater shaker to", + default=2000, + minimum=200, + maximum=3000, + unit="rpm", + ) + parameters.add_str( + variable_name="mount_pos", + display_name="Mount Position", + description="What mount to use", + choices=[ + {"display_name": "Left Mount", "value": "left"}, + {"display_name": "Right Mount", "value": "right"}, + ], + default="left", + ) + parameters.add_float( + variable_name="dot_bottom", + display_name=".bottom", + description="Lowest value pipette will go to.", + default=0.5, + choices=[ + {"display_name": "0.0", "value": 0.0}, + {"display_name": "0.1", "value": 0.1}, + {"display_name": "0.2", "value": 0.2}, + {"display_name": "0.3", "value": 0.3}, + {"display_name": "0.4", "value": 0.4}, + {"display_name": "0.5", "value": 0.5}, + {"display_name": "0.6", "value": 0.6}, + {"display_name": "0.7", "value": 0.7}, + {"display_name": "0.8", "value": 0.8}, + {"display_name": "0.9", "value": 0.9}, + {"display_name": "1.0", "value": 1.0}, + ], + ) + + +def run(ctx: protocol_api.ProtocolContext) -> None: + """Protoco Set up.""" + heater_shaker_speed = ctx.params.heater_shaker_speed # type: ignore[attr-defined] + mount_pos = ctx.params.mount_pos # type: ignore[attr-defined] + dot_bottom = ctx.params.dot_bottom # type: ignore[attr-defined] + trash_chute = False # If this is true, trash chute is loaded in D3, otherwise trash bin is loaded there + USE_GRIPPER = True + dry_run = False + TIP_TRASH = ( + False # True = Used tips go in Trash, False = Used tips go back into rack + ) + mount = mount_pos + res_type = "nest_12_reservoir_15ml" + temp_mod = True + + num_samples = 8 + wash1_vol = 500 + wash2_vol = wash3_vol = 900 + lysis_vol = 200 + sample_vol = 10 # Sample should be pelleted tissue/bacteria/cells + bind_vol = 600 + bind2_vol = 500 + elution_vol = 75 + + # Protocol Parameters + deepwell_type = "nest_96_wellplate_2ml_deep" + + if not dry_run: + settling_time = 2.0 + lysis_incubation = 30.0 + else: + settling_time = 0.25 + lysis_incubation = 0.25 + PK_vol = 20.0 + bead_vol = 25.0 + starting_vol = lysis_vol + sample_vol + binding_buffer_vol = bind_vol + bead_vol + if trash_chute: + ctx.load_waste_chute() + else: + ctx.load_trash_bin("A3") + hs_string = "heaterShakerModuleV1" + h_s: HeaterShakerContext = ctx.load_module(hs_string, "D1") # type: ignore[assignment] + h_s_adapter = h_s.load_adapter("opentrons_96_deep_well_adapter") + sample_plate = h_s_adapter.load_labware(deepwell_type, "Samples") + h_s.close_labware_latch() + + if temp_mod: + temp: TemperatureModuleContext = ctx.load_module( + "temperature module gen2", "D3" + ) # type: ignore[assignment] + temp_block = temp.load_adapter("opentrons_96_well_aluminum_block") + elutionplate = temp_block.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", "Elution Plate" + ) + else: + elutionplate = ctx.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", "A3", "Elution Plate" + ) + + magblock = ctx.load_module("magneticBlockV1", "C1") + waste = ( + ctx.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") + .wells()[0] + .top() + ) + res1 = ctx.load_labware(res_type, "D2", "reagent reservoir 1") + res2 = ctx.load_labware(res_type, "C2", "reagent reservoir 2") + num_cols = math.ceil(num_samples / 8) + + # Load tips and combine all similar boxes + tips1000 = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "A1", "Tips 1") + tips1001 = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "A2", "Tips 2") + tips1002 = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "B1", "Tips 3") + tips = [*tips1000.wells()[num_samples:96], *tips1001.wells(), *tips1002.wells()] + tips_sn = tips1000.wells()[:num_samples] + # load instruments + m1000 = ctx.load_instrument("flex_8channel_1000", mount) + + """ + Here is where you can define the locations of your reagents. + """ + lysis_ = res1.wells()[0] + binding_buffer = res1.wells()[1:4] + bind2_res = res1.wells()[4:6] + wash1 = res1.wells()[6:8] + elution_solution = res1.wells()[-1] + wash2 = res2.wells()[:6] + wash3 = res2.wells()[6:] + + samples_m = sample_plate.rows()[0][:num_cols] + elution_samples_m = elutionplate.rows()[0][:num_cols] + # Redefine per well for liquid definitions + samps = sample_plate.wells()[: (8 * num_cols)] + + colors = [ + "#008000", + "#008000", + "#A52A2A", + "#A52A2A", + "#00FFFF", + "#0000FF", + "#800080", + "#ADD8E6", + "#FF0000", + "#FFFF00", + "#FF00FF", + "#00008B", + "#7FFFD4", + "#FFC0CB", + "#FFA500", + "#00FF00", + "#C0C0C0", + ] + + locations: List[Union[List[Well], Well]] = [ + lysis_, + lysis_, + binding_buffer, + binding_buffer, + bind2_res, + wash1, + wash2, + wash3, + elution_solution, + ] + vols = [ + lysis_vol, + PK_vol, + bead_vol, + bind_vol, + bind2_vol, + wash1_vol, + wash2_vol, + wash3_vol, + elution_vol, + ] + liquids = [ + "Lysis", + "PK", + "Beads", + "Binding", + "Binding 2", + "Wash 1", + "Wash 2", + "Wash 3", + "Final Elution", + ] + + # Defining liquids per sample well + samples = ctx.define_liquid( + name="Samples", description="Samples", display_color="#C0C0C0" + ) + for i in samps: + i.load_liquid(liquid=samples, volume=0) + + delete = len(colors) - len(liquids) + + if delete >= 1: + for i_del in range(delete): + colors.pop(-1) + + # Defining liquids per reservoir well + def liquids_(liq_type: str, location: Union[Well, List[Well]], color, vol: float): + sampnum = 8 * (math.ceil(num_samples / 8)) + """ + Takes an individual liquid at a time and adds the color to the well + in the description. + """ + # Volume Calculation + if liq_type == "PK": + extra_samples = math.ceil(1500 / lysis_vol) + + elif liq_type == "Beads": + extra_samples = math.ceil(1500 / bind_vol) + + else: + extra_samples = math.ceil(1500 / vol) + + # Defining and assigning liquids to wells + if isinstance(location, list): + limit = sample_max / len(location) # Calculates samples/ res well + iterations = math.ceil(sampnum / limit) + left = sampnum - limit + while left > limit: + left = left - limit + if left > 0: + last_iteration_samp_num = left + elif left < 0: + last_iteration_samp_num = sampnum + else: + last_iteration_samp_num = limit + + samples_per_well = [] + + for i in range(iterations): + # append the left over on the last iteration + if i == (iterations - 1): + samples_per_well.append(last_iteration_samp_num) + else: + samples_per_well.append(limit) + + liq = ctx.define_liquid( + name=str(liq_type), description=str(liq_type), display_color=color + ) + for sample, well in zip( + samples_per_well, location[: len(samples_per_well)] + ): + v = vol * (sample + extra_samples) + well.load_liquid(liquid=liq, volume=v) + else: + v = vol * (sampnum + extra_samples) + liq = ctx.define_liquid( + name=str(liq_type), description=str(liq_type), display_color=color + ) + location.load_liquid(liquid=liq, volume=v) + + for x, (ll, l, c, v) in enumerate(zip(liquids, locations, colors, vols)): + liquids_(ll, l, c, v) + + m1000.flow_rate.aspirate = 300 + m1000.flow_rate.dispense = 300 + m1000.flow_rate.blow_out = 300 + + def tiptrack(pip, tipbox): + global tip1k + global drop_count + if tipbox == tips: + m1000.pick_up_tip(tipbox[int(tip1k)]) + tip1k = tip1k + 8 + + drop_count = drop_count + 8 + if drop_count >= 150: + drop_count = 0 + ctx.pause("Please empty the waste bin of all the tips before continuing.") + + def blink(): + for i in range(3): + ctx.set_rail_lights(True) + ctx.delay(minutes=0.01666667) + ctx.set_rail_lights(False) + ctx.delay(minutes=0.01666667) + + def remove_supernatant(vol): + ctx.comment("-----Removing Supernatant-----") + m1000.flow_rate.aspirate = 30 + num_trans = math.ceil(vol / 980) + vol_per_trans = vol / num_trans + + def _waste_track(vol): + global waste_vol + waste_vol = waste_vol + (vol * 8) + if waste_vol >= 185000: + m1000.home() + blink() + ctx.pause("Please empty liquid waste before resuming.") + waste_vol = 0 + + for i, m in enumerate(samples_m): + m1000.pick_up_tip(tips_sn[8 * i]) + loc = m.bottom(dot_bottom) + for _ in range(num_trans): + if m1000.current_volume > 0: + # void air gap if necessary + m1000.dispense(m1000.current_volume, m.top()) + m1000.move_to(m.center()) + m1000.transfer(vol_per_trans, loc, waste, new_tip="never", air_gap=20) + m1000.blow_out(waste) + m1000.air_gap(20) + m1000.drop_tip(tips_sn[8 * i]) if TIP_TRASH == True else m1000.return_tip() + m1000.flow_rate.aspirate = 300 + + # Transfer from Magdeck plate to H-S + h_s.open_labware_latch() + ctx.move_labware(sample_plate, h_s_adapter, use_gripper=USE_GRIPPER) + h_s.close_labware_latch() + + def bead_mixing(well, pip, mvol, reps=8): + """ + 'mixing' will mix liquid that contains beads. This will be done by + aspirating from the bottom of the well and dispensing from the top as to + mix the beads with the other liquids as much as possible. Aspiration and + dispensing will also be reversed for a short to to ensure maximal mixing. + param well: The current well that the mixing will occur in. + param pip: The pipet that is currently attached/ being used. + param mvol: The volume that is transferred before the mixing steps. + param reps: The number of mix repetitions that should occur. Note~ + During each mix rep, there are 2 cycles of aspirating from bottom, + dispensing at the top and 2 cycles of aspirating from middle, + dispensing at the bottom + """ + center = well.top().move(types.Point(x=0, y=0, z=5)) + aspbot = well.bottom().move(types.Point(x=0, y=2, z=1)) + asptop = well.bottom().move(types.Point(x=0, y=-2, z=2)) + disbot = well.bottom().move(types.Point(x=0, y=2, z=3)) + distop = well.top().move(types.Point(x=0, y=1, z=-5)) + + if mvol > 1000: + mvol = 1000 + + vol = mvol * 0.9 + + pip.flow_rate.aspirate = 500 + pip.flow_rate.dispense = 500 + + pip.move_to(center) + for _ in range(reps): + pip.aspirate(vol, aspbot) + pip.dispense(vol, distop) + pip.aspirate(vol, asptop) + pip.dispense(vol, disbot) + if _ == reps - 1: + pip.flow_rate.aspirate = 150 + pip.flow_rate.dispense = 100 + pip.aspirate(vol, aspbot) + pip.dispense(vol, aspbot) + + pip.flow_rate.aspirate = 300 + pip.flow_rate.dispense = 300 + + def mixing(well, pip, mvol, reps=8): + """ + 'mixing' will mix liquid that contains beads. This will be done by + aspirating from the bottom of the well and dispensing from the top as to + mix the beads with the other liquids as much as possible. Aspiration and + dispensing will also be reversed for a short to to ensure maximal mixing. + param well: The current well that the mixing will occur in. + param pip: The pipet that is currently attached/ being used. + param mvol: The volume that is transferred before the mixing steps. + param reps: The number of mix repetitions that should occur. Note~ + During each mix rep, there are 2 cycles of aspirating from bottom, + dispensing at the top and 2 cycles of aspirating from middle, + dispensing at the bottom + """ + center = well.top(5) + asp = well.bottom(1) + disp = well.top(-8) + + if mvol > 1000: + mvol = 1000 + + vol = mvol * 0.9 + + pip.flow_rate.aspirate = 500 + pip.flow_rate.dispense = 500 + + pip.move_to(center) + for _ in range(reps): + pip.aspirate(vol, asp) + pip.dispense(vol, disp) + pip.aspirate(vol, asp) + pip.dispense(vol, disp) + if _ == reps - 1: + pip.flow_rate.aspirate = 150 + pip.flow_rate.dispense = 100 + pip.aspirate(vol, asp) + pip.dispense(vol, asp) + + pip.flow_rate.aspirate = 300 + pip.flow_rate.dispense = 300 + + def lysis(vol, source): + ctx.comment("-----Beginning Lysis Steps-----") + ctx.pause(msg="\n Hello \n - step 1 \n - step 2") + num_transfers = math.ceil(vol / 980) + tiptrack(m1000, tips) + for i in range(num_cols): + src = source + tvol = vol / num_transfers + # Mix Shield and PK before transferring first time + if i == 0: + for x in range(3 if not dry_run else 1): + m1000.aspirate(vol, src.bottom(1)) + m1000.dispense(vol, src.bottom(8)) + # Transfer Shield and PK + for t in range(num_transfers): + m1000.require_liquid_presence(src) + m1000.aspirate(tvol, src.bottom(1)) + m1000.air_gap(10) + m1000.dispense(m1000.current_volume, samples_m[i].top()) + + # Mix shield and pk with samples + for i in range(num_cols): + if i != 0: + tiptrack(m1000, tips) + mixing(samples_m[i], m1000, tvol, reps=5 if not dry_run else 1) + m1000.drop_tip() if TIP_TRASH == True else m1000.return_tip() + + h_s.set_and_wait_for_shake_speed(heater_shaker_speed) + speed_val = heater_shaker_speed + ctx.delay( + minutes=lysis_incubation if not dry_run else 0.25, + msg="Shake at " + str(speed_val) + " rpm for 30 minutes.", + ) + h_s.deactivate_shaker() + + def bind(vol1, vol2): + """ + `bind` will perform magnetic bead binding on each sample in the + deepwell plate. Each channel of binding beads will be mixed before + transfer, and the samples will be mixed with the binding beads after + the transfer. The magnetic deck activates after the addition to all + samples, and the supernatant is removed after bead bining. + :param vol (float): The amount of volume to aspirate from the elution + buffer source and dispense to each well containing + beads. + :param park (boolean): Whether to save sample-corresponding tips + between adding elution buffer and transferring + supernatant to the final clean elutions PCR + plate. + """ + ctx.comment("-----Beginning Binding Steps-----") + for i, well in enumerate(samples_m): + tiptrack(m1000, tips) + num_trans = math.ceil(vol1 / 980) + vol_per_trans = vol1 / num_trans + source = binding_buffer[i // 2] + if i == 0: + reps = 5 + else: + reps = 2 + bead_mixing(source, m1000, vol_per_trans, reps=reps if not dry_run else 1) + # Transfer beads and binding from source to H-S plate + for t in range(num_trans): + if m1000.current_volume > 0: + # void air gap if necessary + m1000.dispense(m1000.current_volume, source.top()) + m1000.require_liquid_presence(source) + m1000.transfer( + vol_per_trans, source, well.top(), air_gap=20, new_tip="never" + ) + m1000.air_gap(20) + bead_mixing(well, m1000, vol_per_trans, reps=8 if not dry_run else 1) + m1000.blow_out() + m1000.air_gap(10) + m1000.drop_tip() if TIP_TRASH == True else m1000.return_tip() + + h_s.set_and_wait_for_shake_speed(heater_shaker_speed * 0.9) + speed_val = heater_shaker_speed * 0.9 + ctx.delay( + minutes=10 if not dry_run else 0.25, + msg="Shake at " + str(speed_val) + " rpm for 10 minutes.", + ) + h_s.deactivate_shaker() + + # Transfer from H-S plate to Magdeck plate + h_s.open_labware_latch() + ctx.move_labware(sample_plate, magblock, use_gripper=USE_GRIPPER) + h_s.close_labware_latch() + + for bindi in np.arange( + settling_time + 1, 0, -0.5 + ): # Settling time delay with countdown timer + ctx.delay( + minutes=0.5, + msg="There are " + str(bindi) + " minutes left in the incubation.", + ) + + # remove initial supernatant + remove_supernatant(vol1 + starting_vol) + + ctx.comment("-----Beginning Bind #2 Steps-----") + tiptrack(m1000, tips) + for i, well in enumerate(samples_m): + num_trans = math.ceil(vol2 / 980) + vol_per_trans = vol2 / num_trans + source = bind2_res[i // 3] + if i == 0 or i == 3: + height = 10 + else: + height = 1 + # Transfer beads and binding from source to H-S plate + for t in range(num_trans): + if m1000.current_volume > 0: + # void air gap if necessary + m1000.dispense(m1000.current_volume, source.top()) + m1000.transfer( + vol_per_trans, + source.bottom(height), + well.top(), + air_gap=20, + new_tip="never", + ) + m1000.air_gap(20) + + for i in range(num_cols): + if i != 0: + tiptrack(m1000, tips) + bead_mixing( + samples_m[i], m1000, vol_per_trans, reps=3 if not dry_run else 1 + ) + m1000.drop_tip() if TIP_TRASH == True else m1000.return_tip() + + h_s.set_and_wait_for_shake_speed(heater_shaker_speed) + speed_val = heater_shaker_speed + ctx.delay( + minutes=1 if not dry_run else 0.25, + msg="Shake at " + str(speed_val) + " rpm for 1 minutes.", + ) + h_s.deactivate_shaker() + + # Transfer from H-S plate to Magdeck plate + h_s.open_labware_latch() + ctx.move_labware(sample_plate, magblock, use_gripper=USE_GRIPPER) + h_s.close_labware_latch() + + for bindi in np.arange( + settling_time + 1, 0, -0.5 + ): # Settling time delay with countdown timer + ctx.delay( + minutes=0.5, + msg="There are " + str(bindi) + " minutes left in the incubation.", + ) + + # remove initial supernatant + remove_supernatant(vol2 + 25) + + def wash(vol, source): + + global whichwash # Defines which wash the protocol is on to log on the app + + if source == wash1: + whichwash = 1 + const = 6 // len(source) + if source == wash2: + whichwash = 2 + const = 6 // len(source) + height = 1 + if source == wash3: + whichwash = 3 + const = 6 // len(source) + height = 1 + + ctx.comment("-----Wash #" + str(whichwash) + " is starting now------") + + num_trans = math.ceil(vol / 980) + vol_per_trans = vol / num_trans + + tiptrack(m1000, tips) + for i, m in enumerate(samples_m): + if source == wash1: + if i == 0 or i == 3: + height = 10 + else: + height = 1 + src = source[i // const] + for n in range(num_trans): + if m1000.current_volume > 0: + m1000.dispense(m1000.current_volume, src.top()) + m1000.require_liquid_presence(src) + m1000.transfer( + vol_per_trans, + src.bottom(height), + m.top(), + air_gap=20, + new_tip="never", + ) + m1000.drop_tip() if TIP_TRASH == True else m1000.return_tip() + + h_s.set_and_wait_for_shake_speed(heater_shaker_speed * 0.9) + ctx.delay(minutes=5 if not dry_run else 0.25) + h_s.deactivate_shaker() + + h_s.open_labware_latch() + ctx.move_labware(sample_plate, magblock, use_gripper=USE_GRIPPER) + h_s.close_labware_latch() + + for washi in np.arange( + settling_time, 0, -0.5 + ): # settling time timer for washes + ctx.delay( + minutes=0.5, + msg="There are " + + str(washi) + + " minutes left in wash " + + str(whichwash) + + " incubation.", + ) + + remove_supernatant(vol) + + def elute(vol): + tiptrack(m1000, tips) + for i, m in enumerate(samples_m): + m1000.require_liquid_presence(elution_solution) + m1000.aspirate(vol, elution_solution) + m1000.air_gap(20) + m1000.dispense(m1000.current_volume, m.top(-3)) + m1000.drop_tip() if TIP_TRASH == True else m1000.return_tip() + + h_s.set_and_wait_for_shake_speed(heater_shaker_speed) + speed_val = heater_shaker_speed + ctx.delay( + minutes=5 if not dry_run else 0.25, + msg="Shake at " + str(speed_val) + " rpm for 5 minutes.", + ) + h_s.deactivate_shaker() + + # Transfer back to magnet + h_s.open_labware_latch() + ctx.move_labware(sample_plate, magblock, use_gripper=USE_GRIPPER) + h_s.close_labware_latch() + + for elutei in np.arange(settling_time, 0, -0.5): + ctx.delay( + minutes=0.5, + msg="Incubating on MagDeck for " + str(elutei) + " more minutes.", + ) + + for i, (m, e) in enumerate(zip(samples_m, elution_samples_m)): + tiptrack(m1000, tips) + m1000.flow_rate.dispense = 100 + m1000.flow_rate.aspirate = 25 + m1000.transfer( + vol, m.bottom(dot_bottom), e.bottom(5), air_gap=20, new_tip="never" + ) + m1000.blow_out(e.top(-2)) + m1000.air_gap(20) + m1000.drop_tip() if TIP_TRASH == True else m1000.return_tip() + + m1000.flow_rate.aspirate = 150 + + """ + Here is where you can call the methods defined above to fit your specific + protocol. The normal sequence is: + """ + lysis(lysis_vol, lysis_) + bind(binding_buffer_vol, bind2_vol) + wash(wash1_vol, wash1) + wash(wash2_vol, wash2) + wash(wash3_vol, wash3) + h_s.set_and_wait_for_temperature(55) + if not dry_run: + drybeads = 9.0 # Number of minutes you want to dry for + else: + drybeads = 0.5 + for beaddry in np.arange(drybeads, 0, -0.5): + ctx.delay( + minutes=0.5, + msg="There are " + str(beaddry) + " minutes left in the drying step.", + ) + elute(elution_vol) + h_s.deactivate_heater() diff --git a/abr-testing/abr_testing/protocols/helpers.py b/abr-testing/abr_testing/protocols/helpers.py new file mode 100644 index 00000000000..d7392a8c67e --- /dev/null +++ b/abr-testing/abr_testing/protocols/helpers.py @@ -0,0 +1,19 @@ +"""Helper functions commonly used in protocols.""" + +from opentrons.protocol_api import ProtocolContext, Labware, InstrumentContext +from typing import Tuple + + +def load_common_liquid_setup_labware_and_instruments( + protocol: ProtocolContext, +) -> Tuple[Labware, InstrumentContext]: + """Load Commonly used Labware and Instruments.""" + # Tip rack + tip_rack = protocol.load_labware("opentrons_flex_96_tiprack_1000ul", "D1") + # Pipette + p1000 = protocol.load_instrument( + instrument_name="flex_8channel_1000", mount="left", tip_racks=[tip_rack] + ) + # Source_reservoir + source_reservoir = protocol.load_labware("axygen_1_reservoir_90ml", "C2") + return source_reservoir, p1000 diff --git a/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py new file mode 100644 index 00000000000..c2c4727d9df --- /dev/null +++ b/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py @@ -0,0 +1,59 @@ +"""Plate Filler Protocol for Zymobiomics DNA Extraction.""" +from opentrons import protocol_api +from abr_testing.protocols.helpers import ( + load_common_liquid_setup_labware_and_instruments, +) + + +metadata = { + "protocolName": "PVT1ABR10 Liquids: ZymoBIOMICS Magbead DNA Extraction", + "author": "Rhyann Clarke ", + "source": "Protocol Library", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.20", +} + + +def run(protocol: protocol_api.ProtocolContext) -> None: + """Protocol.""" + # Initiate Labware + source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + + res1 = protocol.load_labware("nest_12_reservoir_15ml", "C3", "R1") + res2 = protocol.load_labware("nest_12_reservoir_15ml", "B3", "R2") + + lysis_and_pk = (3200 + 320) / 8 + beads_and_binding = (275 + 6600) / 8 + binding2 = 5500 / 8 + wash1 = 5500 / 8 + final_elution = 2100 / 8 + wash2 = 9000 / 8 + wash3 = 9000 / 8 + # Fill up Plates + # Res1 + p1000.transfer( + volume=[lysis_and_pk, beads_and_binding, binding2, wash1, final_elution], + source=source_reservoir["A1"].bottom(z=0.2), + dest=[ + res1["A1"].top(), + res1["A2"].top(), + res1["A5"].top(), + res1["A7"].top(), + res1["A12"].top(), + ], + blow_out=True, + blowout_location="source well", + trash=False, + ) + # Res2 + p1000.transfer( + volume=[wash2, wash3], + source=source_reservoir["A1"], + dest=[res2["A1"].top(), res2["A7"].top()], + blow_out=True, + blowout_location="source well", + trash=False, + ) diff --git a/abr-testing/abr_testing/protocols/liquid_setups/11_Dynabeads RIT Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/11_Dynabeads RIT Liquid Setup.py new file mode 100644 index 00000000000..81316be63e3 --- /dev/null +++ b/abr-testing/abr_testing/protocols/liquid_setups/11_Dynabeads RIT Liquid Setup.py @@ -0,0 +1,57 @@ +"""Plate Filler Protocol for Immunoprecipitation by Dynabeads.""" +from opentrons import protocol_api +from abr_testing.protocols.helpers import ( + load_common_liquid_setup_labware_and_instruments, +) + + +metadata = { + "protocolName": "PVT1ABR11 Liquids: Immunoprecipitation by Dynabeads - 96-well", + "author": "Rhyann Clarke ", + "source": "Protocol Library", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.20", +} + + +def run(protocol: protocol_api.ProtocolContext) -> None: + """Protocol.""" + # Deck Setup + source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + + reservoir_wash = protocol.load_labware("nest_12_reservoir_15ml", "D2", "Reservoir") + sample_plate = protocol.load_labware( + "nest_96_wellplate_2ml_deep", "C3", "Sample Plate" + ) + + columns = [ + "A1", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "A8", + "A9", + "A10", + "A11", + "A12", + ] + # 1 column 6000 uL + p1000.pick_up_tip() + for i in columns: + p1000.aspirate(750, source_reservoir["A1"].bottom(z=0.5)) + p1000.dispense(750, reservoir_wash[i].top()) + p1000.blow_out(location=source_reservoir["A1"].top()) + p1000.return_tip() + # Nest 96 Deep Well Plate 2 mL: 250 uL per well + p1000.pick_up_tip() + for n in columns: + p1000.aspirate(250, source_reservoir["A1"].bottom(z=0.5)) + p1000.dispense(250, sample_plate[n].bottom(z=1)) + p1000.blow_out(location=source_reservoir["A1"].top()) + p1000.return_tip() diff --git a/abr-testing/abr_testing/protocols/liquid_setups/12_KAPA HyperPlus Library Prep Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/12_KAPA HyperPlus Library Prep Liquid Setup.py new file mode 100644 index 00000000000..d27693df67e --- /dev/null +++ b/abr-testing/abr_testing/protocols/liquid_setups/12_KAPA HyperPlus Library Prep Liquid Setup.py @@ -0,0 +1,79 @@ +"""KAPA HyperPlus Library Preparation Liquid Setup.""" +from opentrons import protocol_api +from abr_testing.protocols.helpers import ( + load_common_liquid_setup_labware_and_instruments, +) + + +metadata = { + "protocolName": "PVT1ABR12: KAPA HyperPlus Library Preparation Liquid Setup", + "author": "Rhyann Clarke ", + "source": "Protocol Library", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.20", +} + + +def run(protocol: protocol_api.ProtocolContext) -> None: + """Protocol.""" + source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + + reservoir = protocol.load_labware("nest_96_wellplate_2ml_deep", "D2") # Reservoir + temp_module_res = protocol.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", "B3" + ) + sample_plate_1 = protocol.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", "D3" + ) # Sample Plate + sample_plate_2 = protocol.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", "C3" + ) # Sample Plate + + # Sample Plate 1 Prep: dispense 17 ul into column 1 total 136 ul + p1000.transfer( + volume=136, + source=source_reservoir["A1"].bottom(z=0.5), + dest=sample_plate_1["A1"], + blow_out=True, + blowout_location="source well", + trash=False, + ) + + # Sample Plate 2 Prep: dispense 17 ul into column 1 total 136 ul + p1000.transfer( + volume=136, + source=source_reservoir["A1"].bottom(z=0.5), + dest=sample_plate_2["A1"], + blow_out=True, + blowout_location="source well", + trash=False, + ) + + # Reservoir Plate Prep: + p1000.transfer( + volume=[1214.4, 396, 352, 352], + source=source_reservoir["A1"].bottom(z=0.5), + dest=[reservoir["A1"], reservoir["A4"], reservoir["A5"], reservoir["A6"]], + blow_out=True, + blowout_location="source well", + trash=False, + ) + + # Temp Module Res Prep: dispense 30 and 200 ul into columns 1 and 3 - total 1840 ul + p1000.transfer( + volume=[80, 88, 132, 200, 200], + source=source_reservoir["A1"].bottom(z=0.5), + dest=[ + temp_module_res["A1"], + temp_module_res["A2"], + temp_module_res["A3"], + temp_module_res["A4"], + temp_module_res["A5"], + ], + blow_out=True, + blowout_location="source well", + trash=False, + ) diff --git a/abr-testing/abr_testing/protocols/liquid_setups/1_Simple normalize long Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/1_Simple normalize long Liquid Setup.py new file mode 100644 index 00000000000..e0a75adfe84 --- /dev/null +++ b/abr-testing/abr_testing/protocols/liquid_setups/1_Simple normalize long Liquid Setup.py @@ -0,0 +1,35 @@ +"""Plate Filler Protocol for Simple Normalize Long.""" +from opentrons import protocol_api +from abr_testing.protocols.helpers import ( + load_common_liquid_setup_labware_and_instruments, +) + +metadata = { + "protocolName": "DVT1ABR1 Liquids: Simple Normalize Long", + "author": "Rhyann clarke ", + "source": "Protocol Library", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.20", +} + + +def run(protocol: protocol_api.ProtocolContext) -> None: + """Protocol.""" + # Initiate Labware + source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + reservoir = protocol.load_labware("nest_12_reservoir_15ml", "D2", "Reservoir") + # Transfer Liquid + vol = 5400 / 8 + columns = ["A1", "A2", "A3", "A4", "A5"] + for i in columns: + p1000.transfer( + vol, + source=source_reservoir["A1"].bottom(z=0.5), + dest=reservoir[i].top(), + blowout=True, + blowout_location="source well", + trash=False, + ) diff --git a/abr-testing/abr_testing/protocols/liquid_setups/2_BMS_PCR_protocol Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/2_BMS_PCR_protocol Liquid Setup.py new file mode 100644 index 00000000000..c374a586532 --- /dev/null +++ b/abr-testing/abr_testing/protocols/liquid_setups/2_BMS_PCR_protocol Liquid Setup.py @@ -0,0 +1,33 @@ +"""Plate Filler Protocol for Simple Normalize Long.""" +from opentrons import protocol_api +from abr_testing.protocols.helpers import ( + load_common_liquid_setup_labware_and_instruments, +) + + +metadata = { + "protocolName": "DVT1ABR2 Liquids: BMS PCR Protocol", + "author": "Rhyann clarke ", + "source": "Protocol Library", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.20", +} + + +def run(protocol: protocol_api.ProtocolContext) -> None: + """Protocol.""" + # Initiate Labware + source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + pcr_plate_1 = protocol.load_labware("nest_12_reservoir_15ml", "C3", "PCR Plate 1") + pcr_plate_2 = protocol.load_labware("nest_12_reservoir_15ml", "B3", "PCR Plate 2") + # Steps + p1000.pick_up_tip() + p1000.aspirate(200, source_reservoir["A1"]) + # Dispense into plate 1 + p1000.dispense(100, pcr_plate_1["A1"].top()) + # Dispense into plate 2 + p1000.dispense(100, pcr_plate_2["A1"].top()) + p1000.return_tip() diff --git a/abr-testing/abr_testing/protocols/liquid_setups/4_Illumina DNA Enrichment Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/4_Illumina DNA Enrichment Liquid Setup.py new file mode 100644 index 00000000000..dee32fd5e4c --- /dev/null +++ b/abr-testing/abr_testing/protocols/liquid_setups/4_Illumina DNA Enrichment Liquid Setup.py @@ -0,0 +1,87 @@ +"""Illumina DNA Enrichment Liquid Set up.""" +from opentrons import protocol_api +from abr_testing.protocols.helpers import ( + load_common_liquid_setup_labware_and_instruments, +) + +metadata = { + "protocolName": "DVT1ABR4/8: Illumina DNA Enrichment Liquid Set Up", + "author": "Tony Ngumah ", + "source": "Protocol Library", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.20", +} + + +def run(protocol: protocol_api.ProtocolContext) -> None: + """Protocol.""" + source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + + reservoir_1 = protocol.load_labware( + "nest_96_wellplate_2ml_deep", "D2", "Reservoir 1" + ) # Reservoir + reservoir_2 = protocol.load_labware( + "thermoscientificnunc_96_wellplate_1300ul", "D3", "Reservoir 2" + ) # Reservoir + sample_plate_1 = protocol.load_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", "C3", "Sample Plate" + ) # Sample Plate + reagent_plate_1 = protocol.load_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", "B3", "Reagent Plate" + ) # reagent Plate + + # Reagent Plate Prep: dispense liquid into columns 4 - 7 - total 156 ul + p1000.transfer( + volume=[75, 15, 20, 65], + source=source_reservoir["A1"].bottom(z=0.5), + dest=[ + reagent_plate_1["A4"], + reagent_plate_1["A5"], + reagent_plate_1["A6"], + reagent_plate_1["A7"], + ], + blow_out=True, + blowout_location="source well", + trash=False, + ) + + # Reservoir 1 Plate Prep: dispense liquid into columns 1, 2, 4, 5 total 1866 ul + p1000.transfer( + volume=[120, 750, 900, 96], + source=source_reservoir["A1"], + dest=[ + reservoir_1["A1"].top(), + reservoir_1["A2"].top(), + reservoir_1["A4"].top(), + reservoir_1["A5"].top(), + ], + blow_out=True, + blowout_location="source well", + trash=False, + ) + + # Reservoir 2 Plate Prep: dispense liquid into columns 1-9 total 3690 ul + reservoir_2_wells = reservoir_2.wells() + list_of_locations = [well_location.top() for well_location in reservoir_2_wells] + p1000.transfer( + volume=[50, 50, 50, 50, 50, 50, 330, 330, 330, 800, 800, 800], + source=source_reservoir["A1"], + dest=list_of_locations, + blow_out=True, + blowout_location="source well", + trash=False, + ) + + # Sample Plate Prep: total 303 + dest_list = [sample_plate_1["A1"], sample_plate_1["A2"], sample_plate_1["A3"]] + p1000.transfer( + volume=[101, 101, 101], + source=source_reservoir["A1"], + dest=dest_list, + blow_out=True, + blowout_location="source well", + trash=False, + ) diff --git a/abr-testing/abr_testing/protocols/liquid_setups/5_96ch Complex Protocol Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/5_96ch Complex Protocol Liquid Setup.py new file mode 100644 index 00000000000..c1c54e5b2c9 --- /dev/null +++ b/abr-testing/abr_testing/protocols/liquid_setups/5_96ch Complex Protocol Liquid Setup.py @@ -0,0 +1,49 @@ +"""Plate Filler Protocol for 96ch Complex Protocol.""" +from opentrons import protocol_api +from abr_testing.protocols.helpers import ( + load_common_liquid_setup_labware_and_instruments, +) + +metadata = { + "protocolName": "DVT2ABR5 and 6 Liquids: 96ch Complex Protocol", + "author": "Rhyann clarke ", + "source": "Protocol Library", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.16", +} + + +def run(protocol: protocol_api.ProtocolContext) -> None: + """Protocol.""" + # Initiate Labware + source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + + reservoir = protocol.load_labware( + "nest_96_wellplate_2ml_deep", "D2", "Reservoir" + ) # Reservoir + + vol = 500 + + column_list = [ + "A1", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", + "A8", + "A9", + "A10", + "A11", + "A12", + ] + for i in column_list: + p1000.pick_up_tip() + p1000.aspirate(vol, source_reservoir["A1"].bottom(z=0.5)) + p1000.dispense(vol, reservoir[i].top()) + p1000.blow_out(location=source_reservoir["A1"].top()) + p1000.return_tip() diff --git a/abr-testing/abr_testing/protocols/liquid_setups/7_HDQ DNA Bacteria Extraction Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/7_HDQ DNA Bacteria Extraction Liquid Setup.py new file mode 100644 index 00000000000..f4188e4d3d8 --- /dev/null +++ b/abr-testing/abr_testing/protocols/liquid_setups/7_HDQ DNA Bacteria Extraction Liquid Setup.py @@ -0,0 +1,70 @@ +"""Plate Filler Protocol for HDQ DNA Bacteria Extraction.""" +from opentrons import protocol_api +from abr_testing.protocols.helpers import ( + load_common_liquid_setup_labware_and_instruments, +) + + +metadata = { + "protocolName": "PVT1ABR7 Liquids: HDQ DNA Bacteria Extraction", + "author": "Rhyann Clarke ", + "source": "Protocol Library", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.16", +} + + +def run(protocol: protocol_api.ProtocolContext) -> None: + """Protocol.""" + # Deck Setup + source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + + sample_plate = protocol.load_labware( + "nest_96_wellplate_2ml_deep", "C3", "Sample Plate" + ) + elution_plate = protocol.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", "B3", "Elution Plate" + ) + res1 = protocol.load_labware("nest_12_reservoir_15ml", "D2", "reagent reservoir 1") + # Label Reservoirs + well1 = res1["A1"].top() + well3 = res1["A3"].top() + well4 = res1["A4"].top() + well7 = res1["A7"].top() + well10 = res1["A10"].top() + + # Volumes + wash = 600 + al_and_pk = 468 + beads_and_binding = 552 + + # Sample Plate + p1000.transfer( + volume=180, + source=source_reservoir["A1"].bottom(z=0.5), + dest=sample_plate["A1"].top(), + blowout=True, + blowout_location="source well", + trash=False, + ) + # Elution Plate + p1000.transfer( + volume=100, + source=source_reservoir["A1"].bottom(z=0.5), + dest=elution_plate["A1"].top(), + blowout=True, + blowout_location="source well", + trash=False, + ) + # Res 1 + p1000.transfer( + volume=[beads_and_binding, al_and_pk, wash, wash, wash], + source=source_reservoir["A1"].bottom(z=0.5), + dest=[well1, well3, well4, well7, well10], + blowout=True, + blowout_location="source well", + trash=False, + ) diff --git a/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py new file mode 100644 index 00000000000..9ccde013920 --- /dev/null +++ b/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py @@ -0,0 +1,106 @@ +"""Plate Filler Protocol for Thermo MagMax RNA Extraction.""" +from opentrons import protocol_api +from abr_testing.protocols.helpers import ( + load_common_liquid_setup_labware_and_instruments, +) + + +metadata = { + "protocolName": "PVT1ABR9 Liquids: Thermo MagMax RNA Extraction", + "author": "Rhyann Clarke ", + "source": "Protocol Library", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.16", +} + + +def run(protocol: protocol_api.ProtocolContext) -> None: + """Protocol.""" + # Initiate Labware + source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + res1 = protocol.load_labware("nest_12_reservoir_15ml", "D2", "Reservoir") + elution_plate = protocol.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", "C3", "Elution Plate" + ) + sample_plate = protocol.load_labware( + "nest_96_wellplate_2ml_deep", "B3", "Sample Plate" + ) + + # Volumes + elution_vol = 55 + well1 = 8120 / 8 + well2 = 6400 / 8 + well3_7 = 8550 / 8 + sample_vol = 60 + + # Reservoir + p1000.transfer( + volume=[well1, well2, well3_7, well3_7, well3_7, well3_7, well3_7], + source=source_reservoir["A1"].bottom(z=0.2), + dest=[ + res1["A1"].top(), + res1["A2"].top(), + res1["A3"].top(), + res1["A4"].top(), + res1["A5"].top(), + res1["A6"].top(), + res1["A7"].top(), + ], + blow_out=True, + blowout_location="source well", + trash=False, + ) + # Elution Plate + p1000.transfer( + volume=[ + elution_vol, + elution_vol, + elution_vol, + elution_vol, + elution_vol, + elution_vol, + elution_vol, + elution_vol, + elution_vol, + elution_vol, + elution_vol, + elution_vol, + ], + source=source_reservoir["A1"].bottom(z=0.2), + dest=[ + elution_plate["A1"].bottom(z=0.3), + elution_plate["A2"].bottom(z=0.3), + elution_plate["A3"].bottom(z=0.3), + elution_plate["A4"].bottom(z=0.3), + elution_plate["A5"].bottom(z=0.3), + elution_plate["A6"].bottom(z=0.3), + elution_plate["A7"].bottom(z=0.3), + elution_plate["A8"].bottom(z=0.3), + elution_plate["A9"].bottom(z=0.3), + elution_plate["A10"].bottom(z=0.3), + elution_plate["A11"].bottom(z=0.3), + elution_plate["A12"].bottom(z=0.3), + ], + blow_out=True, + blowout_location="source well", + trash=False, + ) + # Sample Plate + p1000.transfer( + volume=[sample_vol, sample_vol, sample_vol, sample_vol, sample_vol, sample_vol], + source=source_reservoir["A1"].bottom(z=0.2), + dest=[ + sample_plate["A7"].top(), + sample_plate["A8"].top(), + sample_plate["A9"].top(), + sample_plate["A10"].top(), + sample_plate["A11"].top(), + sample_plate["A12"].top(), + ], + blow_out=True, + blowout_location="source well", + trash=False, + ) diff --git a/abr-testing/test_debug b/abr-testing/test_debug new file mode 100644 index 00000000000..e69de29bb2d From 30ab75debea008cb8e45b1a92a6a8f07f97cec03 Mon Sep 17 00:00:00 2001 From: rclarke0 Date: Sun, 27 Oct 2024 16:32:58 -0400 Subject: [PATCH 03/13] abr protocols, removed flake complexity for protocols --- abr-testing/.flake8 | 3 +- ... 10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py} | 349 ++--- .../11_Dynabeads_IP_Flex_96well_RIT.py | 252 ++++ .../12_KAPA HyperPlus Library Prep.py | 1254 +++++++++++++++++ ...omplex protocol with single tip Pick Up.py | 424 ++++++ .../api 2.20/7_HDQ_DNA_Bacteria_Flex.py | 561 ++++++++ .../api 2.20/9_Magmax_RNA_Cells_Flex_csv.py | 587 ++++++++ .../protocols/csv_parameters/9_parameters.csv | 2 + abr-testing/abr_testing/protocols/helpers.py | 193 ++- 9 files changed, 3391 insertions(+), 234 deletions(-) rename abr-testing/abr_testing/protocols/api 2.20/{10_ZymoBIOMICS_Magbead_DNA_Cells_Flex_220api.py => 10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py} (65%) create mode 100644 abr-testing/abr_testing/protocols/api 2.20/11_Dynabeads_IP_Flex_96well_RIT.py create mode 100644 abr-testing/abr_testing/protocols/api 2.20/12_KAPA HyperPlus Library Prep.py create mode 100644 abr-testing/abr_testing/protocols/api 2.20/5_96ch complex protocol with single tip Pick Up.py create mode 100644 abr-testing/abr_testing/protocols/api 2.20/7_HDQ_DNA_Bacteria_Flex.py create mode 100644 abr-testing/abr_testing/protocols/api 2.20/9_Magmax_RNA_Cells_Flex_csv.py create mode 100644 abr-testing/abr_testing/protocols/csv_parameters/9_parameters.csv diff --git a/abr-testing/.flake8 b/abr-testing/.flake8 index cc618b04ba2..ec1d7b91184 100644 --- a/abr-testing/.flake8 +++ b/abr-testing/.flake8 @@ -21,4 +21,5 @@ docstring-convention = google noqa-require-code = true -# per-file-ignores = +per-file-ignores = + abr_testing/protocols/*: C901 diff --git a/abr-testing/abr_testing/protocols/api 2.20/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex_220api.py b/abr-testing/abr_testing/protocols/api 2.20/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py similarity index 65% rename from abr-testing/abr_testing/protocols/api 2.20/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex_220api.py rename to abr-testing/abr_testing/protocols/api 2.20/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py index 3ef8d3bbae0..75c3af5b665 100644 --- a/abr-testing/abr_testing/protocols/api 2.20/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex_220api.py +++ b/abr-testing/abr_testing/protocols/api 2.20/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py @@ -3,12 +3,14 @@ from opentrons import types from typing import List, Union from opentrons import protocol_api -from opentrons.protocol_api import Well +from opentrons.protocol_api import Well, InstrumentContext import numpy as np from opentrons.protocol_api.module_contexts import ( HeaterShakerContext, TemperatureModuleContext, + MagneticBlockContext, ) +from abr_testing.protocols import helpers metadata = { "author": "Zach Galluzzo ", @@ -48,60 +50,21 @@ def add_parameters(parameters: protocol_api.ParameterContext) -> None: """Define parameters.""" - parameters.add_int( - variable_name="heater_shaker_speed", - display_name="Heater Shaker Shake Speed", - description="Speed to set the heater shaker to", - default=2000, - minimum=200, - maximum=3000, - unit="rpm", - ) - parameters.add_str( - variable_name="mount_pos", - display_name="Mount Position", - description="What mount to use", - choices=[ - {"display_name": "Left Mount", "value": "left"}, - {"display_name": "Right Mount", "value": "right"}, - ], - default="left", - ) - parameters.add_float( - variable_name="dot_bottom", - display_name=".bottom", - description="Lowest value pipette will go to.", - default=0.5, - choices=[ - {"display_name": "0.0", "value": 0.0}, - {"display_name": "0.1", "value": 0.1}, - {"display_name": "0.2", "value": 0.2}, - {"display_name": "0.3", "value": 0.3}, - {"display_name": "0.4", "value": 0.4}, - {"display_name": "0.5", "value": 0.5}, - {"display_name": "0.6", "value": 0.6}, - {"display_name": "0.7", "value": 0.7}, - {"display_name": "0.8", "value": 0.8}, - {"display_name": "0.9", "value": 0.9}, - {"display_name": "1.0", "value": 1.0}, - ], - ) + helpers.create_hs_speed_parameter(parameters) + helpers.create_pipette_mount_parameter(parameters) + helpers.create_dot_bottom_parameter(parameters) def run(ctx: protocol_api.ProtocolContext) -> None: - """Protoco Set up.""" + """Protocol Set Up.""" heater_shaker_speed = ctx.params.heater_shaker_speed # type: ignore[attr-defined] - mount_pos = ctx.params.mount_pos # type: ignore[attr-defined] + mount = ctx.params.pipette_mount # type: ignore[attr-defined] dot_bottom = ctx.params.dot_bottom # type: ignore[attr-defined] - trash_chute = False # If this is true, trash chute is loaded in D3, otherwise trash bin is loaded there - USE_GRIPPER = True dry_run = False TIP_TRASH = ( False # True = Used tips go in Trash, False = Used tips go back into rack ) - mount = mount_pos res_type = "nest_12_reservoir_15ml" - temp_mod = True num_samples = 8 wash1_vol = 500 @@ -118,37 +81,39 @@ def run(ctx: protocol_api.ProtocolContext) -> None: if not dry_run: settling_time = 2.0 lysis_incubation = 30.0 + bind_time_1 = 10.0 + bind_time_2 = 1.0 + wash_time = 5.0 + drybeads = 9.0 + lysis_rep_1 = 3 + lysis_rep_2 = 5 + bead_reps_2 = 8 else: settling_time = 0.25 lysis_incubation = 0.25 + bind_time_1 = bind_time_2 = wash_time = 0.25 + drybeads = 0.5 + lysis_rep_1 = lysis_rep_2 = bead_reps_2 = 1 PK_vol = 20.0 bead_vol = 25.0 starting_vol = lysis_vol + sample_vol binding_buffer_vol = bind_vol + bead_vol - if trash_chute: - ctx.load_waste_chute() - else: - ctx.load_trash_bin("A3") - hs_string = "heaterShakerModuleV1" - h_s: HeaterShakerContext = ctx.load_module(hs_string, "D1") # type: ignore[assignment] + ctx.load_trash_bin("A3") + h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] h_s_adapter = h_s.load_adapter("opentrons_96_deep_well_adapter") sample_plate = h_s_adapter.load_labware(deepwell_type, "Samples") h_s.close_labware_latch() - if temp_mod: - temp: TemperatureModuleContext = ctx.load_module( - "temperature module gen2", "D3" - ) # type: ignore[assignment] - temp_block = temp.load_adapter("opentrons_96_well_aluminum_block") - elutionplate = temp_block.load_labware( - "opentrons_96_wellplate_200ul_pcr_full_skirt", "Elution Plate" - ) - else: - elutionplate = ctx.load_labware( - "opentrons_96_wellplate_200ul_pcr_full_skirt", "A3", "Elution Plate" - ) - - magblock = ctx.load_module("magneticBlockV1", "C1") + temp: TemperatureModuleContext = ctx.load_module( + helpers.temp_str, "D3" + ) # type: ignore[assignment] + temp_block = temp.load_adapter("opentrons_96_well_aluminum_block") + elutionplate = temp_block.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", "Elution Plate" + ) + magblock: MagneticBlockContext = ctx.load_module( + helpers.mag_str, "C1" + ) # type: ignore[assignment] waste = ( ctx.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") .wells()[0] @@ -183,25 +148,7 @@ def run(ctx: protocol_api.ProtocolContext) -> None: # Redefine per well for liquid definitions samps = sample_plate.wells()[: (8 * num_cols)] - colors = [ - "#008000", - "#008000", - "#A52A2A", - "#A52A2A", - "#00FFFF", - "#0000FF", - "#800080", - "#ADD8E6", - "#FF0000", - "#FFFF00", - "#FF00FF", - "#00008B", - "#7FFFD4", - "#FFC0CB", - "#FFA500", - "#00FF00", - "#C0C0C0", - ] + colors = helpers.liquid_colors locations: List[Union[List[Well], Well]] = [ lysis_, @@ -250,69 +197,58 @@ def run(ctx: protocol_api.ProtocolContext) -> None: for i_del in range(delete): colors.pop(-1) - # Defining liquids per reservoir well - def liquids_(liq_type: str, location: Union[Well, List[Well]], color, vol: float): - sampnum = 8 * (math.ceil(num_samples / 8)) - """ - Takes an individual liquid at a time and adds the color to the well - in the description. - """ - # Volume Calculation - if liq_type == "PK": - extra_samples = math.ceil(1500 / lysis_vol) - - elif liq_type == "Beads": - extra_samples = math.ceil(1500 / bind_vol) + def add_liquid( + liq_type: str, wells: Union[Well, List[Well]], color: str, vol: float + ) -> None: + """Assigns colored liquid to wells based on type and location.""" + total_samples = math.ceil(num_samples / 8) * 8 + + # Calculate extra sample volume based on liquid type + extra_samples = math.ceil( + 1500 + / ( + lysis_vol + if liq_type == "PK" + else bind_vol + if liq_type == "Beads" + else vol + ) + ) - else: - extra_samples = math.ceil(1500 / vol) - - # Defining and assigning liquids to wells - if isinstance(location, list): - limit = sample_max / len(location) # Calculates samples/ res well - iterations = math.ceil(sampnum / limit) - left = sampnum - limit - while left > limit: - left = left - limit - if left > 0: - last_iteration_samp_num = left - elif left < 0: - last_iteration_samp_num = sampnum - else: - last_iteration_samp_num = limit + # Define liquid + liquid = ctx.define_liquid( + name=liq_type, description=liq_type, display_color=color + ) - samples_per_well = [] + # Assign liquid to each well + if isinstance(wells, list): + samples_per_well = [sample_max // len(wells)] * ( + total_samples // (sample_max // len(wells)) + ) + remainder = total_samples % (sample_max // len(wells)) - for i in range(iterations): - # append the left over on the last iteration - if i == (iterations - 1): - samples_per_well.append(last_iteration_samp_num) - else: - samples_per_well.append(limit) + if remainder: + samples_per_well.append(remainder) - liq = ctx.define_liquid( - name=str(liq_type), description=str(liq_type), display_color=color - ) - for sample, well in zip( - samples_per_well, location[: len(samples_per_well)] - ): - v = vol * (sample + extra_samples) - well.load_liquid(liquid=liq, volume=v) + for sample_count, well in zip(samples_per_well, wells): + well.load_liquid( + liquid=liquid, volume=vol * (sample_count + extra_samples) + ) else: - v = vol * (sampnum + extra_samples) - liq = ctx.define_liquid( - name=str(liq_type), description=str(liq_type), display_color=color + wells.load_liquid( + liquid=liquid, volume=vol * (total_samples + extra_samples) ) - location.load_liquid(liquid=liq, volume=v) - for x, (ll, l, c, v) in enumerate(zip(liquids, locations, colors, vols)): - liquids_(ll, l, c, v) + # Apply function for each liquid configuration + for liq, well, color, vol in zip(liquids, locations, colors, vols): + add_liquid(liq, well, color, vol) m1000.flow_rate.aspirate = 300 m1000.flow_rate.dispense = 300 m1000.flow_rate.blow_out = 300 - def tiptrack(pip, tipbox): + def tiptrack(tipbox: List[Well]) -> None: + """Track Tips.""" global tip1k global drop_count if tipbox == tips: @@ -324,28 +260,13 @@ def tiptrack(pip, tipbox): drop_count = 0 ctx.pause("Please empty the waste bin of all the tips before continuing.") - def blink(): - for i in range(3): - ctx.set_rail_lights(True) - ctx.delay(minutes=0.01666667) - ctx.set_rail_lights(False) - ctx.delay(minutes=0.01666667) - - def remove_supernatant(vol): + def remove_supernatant(vol: float) -> None: + """Remove supernatant.""" ctx.comment("-----Removing Supernatant-----") m1000.flow_rate.aspirate = 30 num_trans = math.ceil(vol / 980) vol_per_trans = vol / num_trans - def _waste_track(vol): - global waste_vol - waste_vol = waste_vol + (vol * 8) - if waste_vol >= 185000: - m1000.home() - blink() - ctx.pause("Please empty liquid waste before resuming.") - waste_vol = 0 - for i, m in enumerate(samples_m): m1000.pick_up_tip(tips_sn[8 * i]) loc = m.bottom(dot_bottom) @@ -357,16 +278,17 @@ def _waste_track(vol): m1000.transfer(vol_per_trans, loc, waste, new_tip="never", air_gap=20) m1000.blow_out(waste) m1000.air_gap(20) - m1000.drop_tip(tips_sn[8 * i]) if TIP_TRASH == True else m1000.return_tip() + m1000.drop_tip(tips_sn[8 * i]) if TIP_TRASH else m1000.return_tip() m1000.flow_rate.aspirate = 300 # Transfer from Magdeck plate to H-S - h_s.open_labware_latch() - ctx.move_labware(sample_plate, h_s_adapter, use_gripper=USE_GRIPPER) - h_s.close_labware_latch() + helpers.move_labware_to_hs(ctx, sample_plate, h_s, h_s_adapter) + + def bead_mixing( + well: Well, pip: InstrumentContext, mvol: float, reps: int = 8 + ) -> None: + """Mixing. - def bead_mixing(well, pip, mvol, reps=8): - """ 'mixing' will mix liquid that contains beads. This will be done by aspirating from the bottom of the well and dispensing from the top as to mix the beads with the other liquids as much as possible. Aspiration and @@ -408,8 +330,9 @@ def bead_mixing(well, pip, mvol, reps=8): pip.flow_rate.aspirate = 300 pip.flow_rate.dispense = 300 - def mixing(well, pip, mvol, reps=8): - """ + def mixing(well: Well, pip: InstrumentContext, mvol: float, reps: int = 8) -> None: + """Mixing. + 'mixing' will mix liquid that contains beads. This will be done by aspirating from the bottom of the well and dispensing from the top as to mix the beads with the other liquids as much as possible. Aspiration and @@ -449,17 +372,18 @@ def mixing(well, pip, mvol, reps=8): pip.flow_rate.aspirate = 300 pip.flow_rate.dispense = 300 - def lysis(vol, source): + def lysis(vol: float, source: Well) -> None: + """Lysis.""" ctx.comment("-----Beginning Lysis Steps-----") ctx.pause(msg="\n Hello \n - step 1 \n - step 2") num_transfers = math.ceil(vol / 980) - tiptrack(m1000, tips) + tiptrack(tips) for i in range(num_cols): src = source tvol = vol / num_transfers # Mix Shield and PK before transferring first time if i == 0: - for x in range(3 if not dry_run else 1): + for x in range(lysis_rep_1): m1000.aspirate(vol, src.bottom(1)) m1000.dispense(vol, src.bottom(8)) # Transfer Shield and PK @@ -472,20 +396,15 @@ def lysis(vol, source): # Mix shield and pk with samples for i in range(num_cols): if i != 0: - tiptrack(m1000, tips) - mixing(samples_m[i], m1000, tvol, reps=5 if not dry_run else 1) - m1000.drop_tip() if TIP_TRASH == True else m1000.return_tip() + tiptrack(tips) + mixing(samples_m[i], m1000, tvol, reps=lysis_rep_2) + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() - h_s.set_and_wait_for_shake_speed(heater_shaker_speed) - speed_val = heater_shaker_speed - ctx.delay( - minutes=lysis_incubation if not dry_run else 0.25, - msg="Shake at " + str(speed_val) + " rpm for 30 minutes.", - ) - h_s.deactivate_shaker() + helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, lysis_incubation, True) + + def bind(vol1: float, vol2: float) -> None: + """Binding. - def bind(vol1, vol2): - """ `bind` will perform magnetic bead binding on each sample in the deepwell plate. Each channel of binding beads will be mixed before transfer, and the samples will be mixed with the binding beads after @@ -501,7 +420,7 @@ def bind(vol1, vol2): """ ctx.comment("-----Beginning Binding Steps-----") for i, well in enumerate(samples_m): - tiptrack(m1000, tips) + tiptrack(tips) num_trans = math.ceil(vol1 / 980) vol_per_trans = vol1 / num_trans source = binding_buffer[i // 2] @@ -520,23 +439,15 @@ def bind(vol1, vol2): vol_per_trans, source, well.top(), air_gap=20, new_tip="never" ) m1000.air_gap(20) - bead_mixing(well, m1000, vol_per_trans, reps=8 if not dry_run else 1) + bead_mixing(well, m1000, vol_per_trans, reps=bead_reps_2) m1000.blow_out() m1000.air_gap(10) - m1000.drop_tip() if TIP_TRASH == True else m1000.return_tip() + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() - h_s.set_and_wait_for_shake_speed(heater_shaker_speed * 0.9) - speed_val = heater_shaker_speed * 0.9 - ctx.delay( - minutes=10 if not dry_run else 0.25, - msg="Shake at " + str(speed_val) + " rpm for 10 minutes.", - ) - h_s.deactivate_shaker() + helpers.set_hs_speed(ctx, h_s, heater_shaker_speed * 0.9, bind_time_1, True) # Transfer from H-S plate to Magdeck plate - h_s.open_labware_latch() - ctx.move_labware(sample_plate, magblock, use_gripper=USE_GRIPPER) - h_s.close_labware_latch() + helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) for bindi in np.arange( settling_time + 1, 0, -0.5 @@ -550,7 +461,7 @@ def bind(vol1, vol2): remove_supernatant(vol1 + starting_vol) ctx.comment("-----Beginning Bind #2 Steps-----") - tiptrack(m1000, tips) + tiptrack(tips) for i, well in enumerate(samples_m): num_trans = math.ceil(vol2 / 980) vol_per_trans = vol2 / num_trans @@ -575,24 +486,15 @@ def bind(vol1, vol2): for i in range(num_cols): if i != 0: - tiptrack(m1000, tips) + tiptrack(tips) bead_mixing( samples_m[i], m1000, vol_per_trans, reps=3 if not dry_run else 1 ) - m1000.drop_tip() if TIP_TRASH == True else m1000.return_tip() - - h_s.set_and_wait_for_shake_speed(heater_shaker_speed) - speed_val = heater_shaker_speed - ctx.delay( - minutes=1 if not dry_run else 0.25, - msg="Shake at " + str(speed_val) + " rpm for 1 minutes.", - ) - h_s.deactivate_shaker() + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() + helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, bind_time_2, True) # Transfer from H-S plate to Magdeck plate - h_s.open_labware_latch() - ctx.move_labware(sample_plate, magblock, use_gripper=USE_GRIPPER) - h_s.close_labware_latch() + helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) for bindi in np.arange( settling_time + 1, 0, -0.5 @@ -605,8 +507,8 @@ def bind(vol1, vol2): # remove initial supernatant remove_supernatant(vol2 + 25) - def wash(vol, source): - + def wash(vol: float, source: List[Well]) -> None: + """Wash Steps.""" global whichwash # Defines which wash the protocol is on to log on the app if source == wash1: @@ -626,7 +528,7 @@ def wash(vol, source): num_trans = math.ceil(vol / 980) vol_per_trans = vol / num_trans - tiptrack(m1000, tips) + tiptrack(tips) for i, m in enumerate(samples_m): if source == wash1: if i == 0 or i == 3: @@ -645,15 +547,10 @@ def wash(vol, source): air_gap=20, new_tip="never", ) - m1000.drop_tip() if TIP_TRASH == True else m1000.return_tip() - - h_s.set_and_wait_for_shake_speed(heater_shaker_speed * 0.9) - ctx.delay(minutes=5 if not dry_run else 0.25) - h_s.deactivate_shaker() + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() + helpers.set_hs_speed(ctx, h_s, heater_shaker_speed * 0.9, wash_time, True) - h_s.open_labware_latch() - ctx.move_labware(sample_plate, magblock, use_gripper=USE_GRIPPER) - h_s.close_labware_latch() + helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) for washi in np.arange( settling_time, 0, -0.5 @@ -669,27 +566,19 @@ def wash(vol, source): remove_supernatant(vol) - def elute(vol): - tiptrack(m1000, tips) + def elute(vol: float) -> None: + tiptrack(tips) for i, m in enumerate(samples_m): m1000.require_liquid_presence(elution_solution) m1000.aspirate(vol, elution_solution) m1000.air_gap(20) m1000.dispense(m1000.current_volume, m.top(-3)) - m1000.drop_tip() if TIP_TRASH == True else m1000.return_tip() + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() - h_s.set_and_wait_for_shake_speed(heater_shaker_speed) - speed_val = heater_shaker_speed - ctx.delay( - minutes=5 if not dry_run else 0.25, - msg="Shake at " + str(speed_val) + " rpm for 5 minutes.", - ) - h_s.deactivate_shaker() + helpers.set_hs_speed(ctx, h_s, heater_shaker_speed * 0.9, wash_time, True) # Transfer back to magnet - h_s.open_labware_latch() - ctx.move_labware(sample_plate, magblock, use_gripper=USE_GRIPPER) - h_s.close_labware_latch() + helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) for elutei in np.arange(settling_time, 0, -0.5): ctx.delay( @@ -698,7 +587,7 @@ def elute(vol): ) for i, (m, e) in enumerate(zip(samples_m, elution_samples_m)): - tiptrack(m1000, tips) + tiptrack(tips) m1000.flow_rate.dispense = 100 m1000.flow_rate.aspirate = 25 m1000.transfer( @@ -706,7 +595,7 @@ def elute(vol): ) m1000.blow_out(e.top(-2)) m1000.air_gap(20) - m1000.drop_tip() if TIP_TRASH == True else m1000.return_tip() + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() m1000.flow_rate.aspirate = 150 @@ -720,10 +609,6 @@ def elute(vol): wash(wash2_vol, wash2) wash(wash3_vol, wash3) h_s.set_and_wait_for_temperature(55) - if not dry_run: - drybeads = 9.0 # Number of minutes you want to dry for - else: - drybeads = 0.5 for beaddry in np.arange(drybeads, 0, -0.5): ctx.delay( minutes=0.5, diff --git a/abr-testing/abr_testing/protocols/api 2.20/11_Dynabeads_IP_Flex_96well_RIT.py b/abr-testing/abr_testing/protocols/api 2.20/11_Dynabeads_IP_Flex_96well_RIT.py new file mode 100644 index 00000000000..5762c0e3f1f --- /dev/null +++ b/abr-testing/abr_testing/protocols/api 2.20/11_Dynabeads_IP_Flex_96well_RIT.py @@ -0,0 +1,252 @@ +"""Immunoprecipitation by Dynabeads.""" +from opentrons.protocol_api import ProtocolContext, ParameterContext, Well +from opentrons.protocol_api.module_contexts import ( + HeaterShakerContext, + TemperatureModuleContext, + MagneticBlockContext, +) +from abr_testing.protocols import helpers +from typing import List, Union + +metadata = { + "protocolName": "Immunoprecipitation by Dynabeads - (Reagents in 15 mL tubes)", + "author": "Boren Lin, Opentrons", + "description": "Isolates protein from liquid samples using protein A /G coupled magnetic beads", +} + +requirements = { + "robotType": "OT-3", + "apiLevel": "2.20", +} + + +def add_parameters(parameters: ParameterContext) -> None: + """Define parameters.""" + helpers.create_hs_speed_parameter(parameters) + helpers.create_pipette_mount_parameter(parameters) + helpers.create_dot_bottom_parameter(parameters) + + +NUM_COL = 12 + +MAG_DELAY_MIN = 1 + +BEADS_VOL = 50 +AB_VOL = 50 +SAMPLE_VOL = 200 +WASH_TIMES = 3 +WASH_VOL = 200 +ELUTION_VOL = 50 + +WASTE_VOL_MAX = 275000 + +READY_FOR_SDSPAGE = 0 + +waste_vol_chk = 0.0 +waste_vol = 0.0 + +TIP_TRASH = False + + +def run(ctx: ProtocolContext) -> None: + """Protocol.""" + # defining variables inside def run + heater_shaker_speed = ctx.params.heater_shaker_speed # type: ignore[attr-defined] + ASP_HEIGHT = ctx.params.dot_bottom # type: ignore[attr-defined] + MIX_SPEED = heater_shaker_speed + MIX_SEC = 10 + + # if on deck: + INCUBATION_SPEEND = heater_shaker_speed * 0.5 + INCUBATION_MIN = 60 + # load labware + + sample_plate = ctx.load_labware("nest_96_wellplate_2ml_deep", "B2", "samples") + wash_res = ctx.load_labware("nest_12_reservoir_15ml", "B1", "wash") + reagent_res = ctx.load_labware( + "opentrons_15_tuberack_nest_15ml_conical", "C3", "reagents" + ) + waste_res = ctx.load_labware("nest_1_reservoir_290ml", "D2", "waste") + + tips = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "B3") + tips_sample = ctx.load_labware( + "opentrons_flex_96_tiprack_1000ul", "A2", "sample tips" + ) + tips_sample_loc = tips_sample.wells()[:95] + if READY_FOR_SDSPAGE == 0: + tips_elu = ctx.load_labware( + "opentrons_flex_96_tiprack_1000ul", "A1", "elution tips" + ) + tips_elu_loc = tips_elu.wells()[:95] + tips_reused = ctx.load_labware( + "opentrons_flex_96_tiprack_1000ul", "C2", "reused tips" + ) + tips_reused_loc = tips_reused.wells()[:95] + p1000 = ctx.load_instrument("flex_8channel_1000", "right", tip_racks=[tips]) + p1000_single = ctx.load_instrument("flex_1channel_1000", "left", tip_racks=[tips]) + h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] + h_s_adapter = h_s.load_adapter("opentrons_96_deep_well_adapter") + working_plate = h_s_adapter.load_labware( + "nest_96_wellplate_2ml_deep", "working plate" + ) + + if READY_FOR_SDSPAGE == 0: + temp: TemperatureModuleContext = ctx.load_module( + helpers.temp_str, "D3" + ) # type: ignore[assignment] + final_plate = temp.load_labware( + "opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep", "final plate" + ) + mag: MagneticBlockContext = ctx.load_module(helpers.mag_str, "C1") # type: ignore[assignment] + + # liquids + samples = sample_plate.rows()[0][:NUM_COL] # 1 + beads = reagent_res.wells()[0] # 2 + ab = reagent_res.wells()[1] # 3 + elu = reagent_res.wells()[2] # 4 + wash = wash_res.rows()[0][:NUM_COL] # 5 + waste = waste_res.wells()[0] + working_cols = working_plate.rows()[0][:NUM_COL] # 6 + working_wells = working_plate.wells()[: NUM_COL * 8] # 6 + if READY_FOR_SDSPAGE == 0: + final_cols = final_plate.rows()[0][:NUM_COL] + + def transfer_plate_to_plate( + vol1: float, start: List[Well], end: List[Well], liquid: int + ) -> None: + """Transfer from plate to plate.""" + for i in range(NUM_COL): + if liquid == 1: + p1000.pick_up_tip(tips_sample_loc[i * 8]) + else: + p1000.pick_up_tip(tips_elu_loc[i * 8]) + start_loc = start[i] + end_loc = end[i] + p1000.aspirate(vol1, start_loc.bottom(z=ASP_HEIGHT), rate=2) + p1000.air_gap(10) + p1000.dispense(vol1 + 10, end_loc.bottom(z=15), rate=2) + p1000.blow_out() + p1000.touch_tip() + p1000.return_tip() if not TIP_TRASH else p1000.drop_tip() + + def transfer_well_to_plate( + vol2: float, + start: Union[List[Well], Well], + end: List[Well], + liquid: int, + drop_height: int = -20, + ) -> None: + """Transfer from well to plate.""" + if liquid == 5 and type(start) == List: + p1000.pick_up_tip() + for j in range(NUM_COL): + start_loc = start[j] + p1000.require_liquid_presence(start_loc) + end_loc = end[j] + p1000.aspirate(vol2, start_loc.bottom(z=ASP_HEIGHT), rate=2) + p1000.air_gap(10) + p1000.dispense(vol2 + 10, end_loc.top(z=drop_height), rate=2) + p1000.blow_out() + p1000.return_tip() if not TIP_TRASH else p1000.drop_tip() + + elif type(start) == Well: + p1000_single.pick_up_tip() + vol = vol2 * 8 + p1000_single.mix(5, vol * 0.75, start.bottom(z=ASP_HEIGHT * 5), rate=2) + p1000_single.mix(5, vol * 0.75, start.bottom(z=ASP_HEIGHT * 20), rate=2) + for j in range(NUM_COL): + end_loc_gap = end[j * 8] + if liquid == 2: + p1000_single.mix( + 2, vol * 0.75, start.bottom(z=ASP_HEIGHT * 5), rate=2 + ) + p1000_single.require_liquid_presence(start) + p1000_single.aspirate(vol, start.bottom(z=ASP_HEIGHT * 5), rate=2) + p1000_single.air_gap(10) + p1000_single.dispense(10, end_loc_gap.top(z=-5)) + for jj in range(8): + end_loc = end[j * 8 + jj] + p1000_single.dispense(vol2, end_loc.bottom(z=10), rate=0.75) + p1000_single.touch_tip() + p1000_single.blow_out() + p1000_single.return_tip() if not TIP_TRASH else p1000.drop_tip() + + def discard(vol3: float, start: List[Well]) -> None: + """Discard function.""" + global waste_vol + global waste_vol_chk + if waste_vol_chk >= WASTE_VOL_MAX: + ctx.pause("Empty Liquid Waste") + waste_vol_chk = 0 + waste_vol = 0.0 + for k in range(NUM_COL): + p1000.pick_up_tip(tips_reused_loc[k * 8]) + start_loc = start[k] + end_loc = waste + p1000.aspirate(vol3, start_loc.bottom(z=ASP_HEIGHT), rate=0.3) + p1000.air_gap(10) + p1000.dispense(vol3 + 10, end_loc.top(z=-5), rate=2) + p1000.blow_out() + p1000.return_tip() + waste_vol = vol3 * NUM_COL * 8.0 + waste_vol_chk = waste_vol_chk + waste_vol + + # protocol + + # Add beads, samples and antibody solution + h_s.close_labware_latch() + transfer_well_to_plate(BEADS_VOL, beads, working_wells, 2) + + helpers.move_labware_from_hs_to_mag_block(ctx, working_plate, h_s, mag) + + ctx.delay(minutes=MAG_DELAY_MIN) + discard(BEADS_VOL * 1.1, working_cols) + + helpers.move_labware_to_hs(ctx, working_plate, h_s, h_s_adapter) + + transfer_plate_to_plate(SAMPLE_VOL, samples, working_cols, 1) + transfer_well_to_plate(AB_VOL, ab, working_wells, 3) + + h_s.set_and_wait_for_shake_speed(rpm=MIX_SPEED) + ctx.delay(seconds=MIX_SEC) + + h_s.set_and_wait_for_shake_speed(rpm=INCUBATION_SPEEND) + ctx.delay(seconds=INCUBATION_MIN * 60) + h_s.deactivate_shaker() + + helpers.move_labware_from_hs_to_mag_block(ctx, working_plate, h_s, mag) + + ctx.delay(minutes=MAG_DELAY_MIN) + vol_total = SAMPLE_VOL + AB_VOL + discard(vol_total * 1.1, working_cols) + + # Wash + for _ in range(WASH_TIMES): + helpers.move_labware_to_hs(ctx, working_plate, h_s, h_s_adapter) + + transfer_well_to_plate(WASH_VOL, wash, working_cols, 5) + helpers.set_hs_speed(ctx, h_s, MIX_SPEED, MIX_SEC / 60, True) + helpers.move_labware_from_hs_to_mag_block(ctx, working_plate, h_s, mag) + ctx.delay(minutes=MAG_DELAY_MIN) + discard(WASH_VOL * 1.1, working_cols) + + # Elution + helpers.move_labware_to_hs(ctx, working_plate, h_s, h_s_adapter) + + transfer_well_to_plate(ELUTION_VOL, elu, working_wells, 4) + if READY_FOR_SDSPAGE == 1: + ctx.pause("Seal the Working Plate") + h_s.set_and_wait_for_temperature(70) + helpers.set_hs_speed(ctx, h_s, MIX_SPEED, (MIX_SEC / 60) + 10, True) + h_s.deactivate_heater() + h_s.open_labware_latch() + ctx.pause("Protocol Complete") + + elif READY_FOR_SDSPAGE == 0: + helpers.set_hs_speed(ctx, h_s, MIX_SPEED, (MIX_SEC / 60) + 2, True) + + temp.set_temperature(4) + helpers.move_labware_from_hs_to_mag_block(ctx, working_plate, h_s, mag) + ctx.delay(minutes=MAG_DELAY_MIN) + transfer_plate_to_plate(ELUTION_VOL * 1.1, working_cols, final_cols, 6) + temp.deactivate() diff --git a/abr-testing/abr_testing/protocols/api 2.20/12_KAPA HyperPlus Library Prep.py b/abr-testing/abr_testing/protocols/api 2.20/12_KAPA HyperPlus Library Prep.py new file mode 100644 index 00000000000..d60cfe405fd --- /dev/null +++ b/abr-testing/abr_testing/protocols/api 2.20/12_KAPA HyperPlus Library Prep.py @@ -0,0 +1,1254 @@ +"""KAPA HyperPlus Library Preparation.""" +from opentrons.protocol_api import ( + ProtocolContext, + ParameterContext, + Labware, + Well, + InstrumentContext, +) +from opentrons import types +import math +from abr_testing.protocols import helpers +from opentrons.protocol_api.module_contexts import ( + TemperatureModuleContext, + MagneticBlockContext, + ThermocyclerContext, +) +from opentrons.hardware_control.modules.types import ThermocyclerStep +from typing import List, Tuple, Optional + +metadata = { + "protocolName": "KAPA HyperPlus Library Preparation", + "author": "Your Name ", +} + +requirements = {"robotType": "Flex", "apiLevel": "2.20"} + +tt_50 = 0 +tt_200 = 0 +p50_rack_count = 0 +p200_rack_count = 0 +tip50 = 50 +tip200 = 200 +p50_racks_ondeck = [] +p200_racks_ondeck = [] +p50_racks_offdeck = [] +p200_racks_offdeck = [] + + +def add_parameters(parameters: ParameterContext) -> None: + """Parameters.""" + parameters.add_bool( + variable_name="dry_run", + display_name="Dry Run", + description="Skip incubation delays and shorten mix steps.", + default=False, + ) + parameters.add_bool( + variable_name="trash_tips", + display_name="Trash tip", + description="tip trashes after every use", + default=False, + ) + helpers.create_disposable_lid_parameter(parameters) + parameters.add_int( + variable_name="num_samples", + display_name="number of samples", + description="How many samples to be perform for library prep", + default=8, + minimum=8, + maximum=48, + ) + parameters.add_int( + variable_name="PCR_CYCLES", + display_name="number of PCR Cycles", + description="How many pcr cycles to be perform for library prep", + default=2, + minimum=2, + maximum=16, + ) + + parameters.add_int( + variable_name="Fragmentation_time", + display_name="time on thermocycler", + description="Fragmentation time in thermocycler", + default=10, + minimum=10, + maximum=30, + ) + + +def run(ctx: ProtocolContext) -> None: + """Protocol.""" + USE_GRIPPER = True + trash_tips = ctx.params.trash_tips # type: ignore[attr-defined] + dry_run = ctx.params.dry_run # type: ignore[attr-defined] + REUSE_ETOH_TIPS = False + REUSE_RSB_TIPS = ( + False # Reuse tips for RSB buffer (adding RSB, mixing, and transferring) + ) + REUSE_REMOVE_TIPS = False # Reuse tips for supernatant removal + num_samples = ctx.params.num_samples # type: ignore[attr-defined] + PCRCYCLES = ctx.params.PCR_CYCLES # type: ignore[attr-defined] + disposable_lid = ctx.params.disposable_lid # type: ignore[attr-defined] + Fragmentation_time = 10 + ligation_tc_time = 15 + used_lids: List[Labware] = [] + if dry_run: + trash_tips = False + + num_cols = math.ceil(num_samples / 8) + + # Pre-set parameters + sample_vol = 35 + frag_vol = 15 + end_repair_vol = 10 + adapter_vol = 5 + ligation_vol = 45 + amplification_vol = 30 + bead_vol_1 = 88 + bead_vol_2 = 50 + bead_vol = bead_vol_1 + bead_vol_2 + bead_inc = 2 + rsb_vol_1 = 25 + rsb_vol_2 = 20 + rsb_vol = rsb_vol_1 + rsb_vol_2 + elution_vol = 20 + elution_vol_2 = 17 + etoh_vol = 400 + + # Importing Labware, Modules and Instruments + magblock: MagneticBlockContext = ctx.load_module( + helpers.mag_str, "D2" + ) # type: ignore[assignment] + temp_mod: TemperatureModuleContext = ctx.load_module( + helpers.temp_str, "B3" + ) # type: ignore[assignment] + temp_adapter = temp_mod.load_adapter("opentrons_96_well_aluminum_block") + temp_plate = temp_adapter.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", "Temp Module Reservoir Plate" + ) + + if not dry_run: + temp_mod.set_temperature(4) + tc_mod: ThermocyclerContext = ctx.load_module(helpers.tc_str) # type: ignore[assignment] + # Just in case + tc_mod.open_lid() + + FLP_plate = magblock.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", "FLP Plate" + ) + samples_flp = FLP_plate.rows()[0][:num_cols] + + sample_plate = ctx.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", "D1", "Sample Pate" + ) + + sample_plate_2 = ctx.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", "B2", "Sample Pate" + ) + samples_2 = sample_plate_2.rows()[0][:num_cols] + samples = sample_plate.rows()[0][:num_cols] + reservoir = ctx.load_labware("nest_96_wellplate_2ml_deep", "C2") + + trash = ctx.load_waste_chute() + # Load TC Lids + unused_lids = helpers.load_disposable_lids(ctx, 5, "C3") + # Import Global Variables + + global tip50 + global tip200 + global p50_rack_count + global p200_rack_count + global tt_50 + global tt_200 + + p200 = ctx.load_instrument("flex_8channel_1000", "left") + p50 = ctx.load_instrument("flex_8channel_50", "right") + + Available_on_deck_slots = ["A2", "A3", "B3"] + Available_off_deck_slots = ["A4", "B4"] + p50_racks_to_dump = [] + p200_racks_to_dump = [] + + if REUSE_RSB_TIPS: + Available_on_deck_slots.remove("A3") + tip50_reuse = ctx.load_labware("opentrons_flex_96_tiprack_50ul", "A3") + RSB_tip = [] + p50_rack_count += 1 + tt_50 += 12 + p50.tip_racks.append(tip50_reuse) + ctx.comment(f"Adding 50 ul tip rack #{p50_rack_count}") + for x in range(num_cols): + RSB_tip.append(tip50_reuse.wells()[8 * x]) + tt_50 -= 1 + p50.starting_tip = tip50_reuse.wells()[(len(RSB_tip)) * 8] + + if REUSE_REMOVE_TIPS: + Available_on_deck_slots.remove("A2") + tip200_reuse = ctx.load_labware("opentrons_flex_96_tiprack_200ul", "A2") + RemoveSup_tip = [] + p200_rack_count += 1 + tt_200 += 12 + p200.tip_racks.append(tip200_reuse) + ctx.comment(f"Adding 200 ul tip rack #{p200_rack_count}") + for x in range(num_cols): + RemoveSup_tip.append(tip200_reuse.wells()[8 * x]) + tt_200 -= 1 + p200.starting_tip = tip200_reuse.wells()[(len(RemoveSup_tip)) * 8] + + # Load Reagent Locations in Reservoirs + + # Sample Plate + sample_liq = ctx.define_liquid( + name="Samples", + description="DNA sample of known quantity", + display_color="#C0C0C0", + ) + for well in sample_plate.wells()[: 8 * num_cols]: + well.load_liquid(liquid=sample_liq, volume=sample_vol) + + Final_liq = ctx.define_liquid( + name="Final Library", description="Final Library", display_color="#FFA500" + ) + for well in sample_plate_2.wells()[: 8 * num_cols]: + well.load_liquid(liquid=Final_liq, volume=elution_vol_2) + + # Cold Res + + adapters = temp_plate.rows()[0][:num_cols] # used for filling liquids + adapter_liq = ctx.define_liquid( + name="Adapters", + description="Adapters to ligate onto DNA insert.", + display_color="#A52A2A", + ) + for well in temp_plate.wells()[: 8 * num_cols]: + well.load_liquid(liquid=adapter_liq, volume=adapter_vol * 2) + + end_repair_cols: List[Well] = temp_plate.columns()[ + num_cols + ] # used for filling liquids + er_res = end_repair_cols[0] + er_liq = ctx.define_liquid( + name="End Repair", description="End Repair mix", display_color="#FF00FF" + ) + for well in end_repair_cols: + well.load_liquid( + liquid=er_liq, volume=(end_repair_vol * num_cols) + (0.1 * end_repair_vol) + ) + + frag: List[Well] = temp_plate.columns()[num_cols + 1] + frag_res = frag[0] + frag_liq = ctx.define_liquid( + name="Fragmentation", description="Fragmentation mix", display_color="#00FFFF" + ) + for well in frag: + well.load_liquid( + liquid=frag_liq, volume=(frag_vol * num_cols) + (0.1 * frag_vol) + ) + + ligation: List[Well] = temp_plate.columns()[num_cols + 2] + ligation_res = ligation[0] + ligation_liq = ctx.define_liquid( + name="Ligation", description="Ligation Mix", display_color="#008000" + ) + for well in ligation: + well.load_liquid( + liquid=ligation_liq, volume=(ligation_vol * num_cols) + (0.1 * ligation_vol) + ) + + lib_amplification_wells: List[Well] = temp_plate.columns()[num_cols + 3] + amplification_res = lib_amplification_wells[0] + amp_liq = ctx.define_liquid( + name="Amplification", description="Amplification Mix", display_color="#0000FF" + ) + for well in lib_amplification_wells: + well.load_liquid( + liquid=amp_liq, + volume=(amplification_vol * num_cols) + (0.1 * amplification_vol), + ) + + # Room Temp Res (deepwell) + bead = reservoir.columns()[0] + bead_res = bead[0] + bead_liq = ctx.define_liquid( + name="Ampure Beads", description="Ampure Beads", display_color="#800080" + ) + for well in bead: + well.load_liquid( + liquid=bead_liq, volume=(bead_vol * num_cols) + (0.1 * bead_vol * num_cols) + ) + + rsb = reservoir.columns()[3] + rsb_res = rsb[0] + rsb_liq = ctx.define_liquid( + name="RSB", description="Resuspension buffer", display_color="#FFFF00" + ) + for well in rsb: + well.load_liquid( + liquid=rsb_liq, volume=(rsb_vol * num_cols) + (0.1 * rsb_vol * num_cols) + ) + + etoh1 = reservoir.columns()[4] + etoh1_res = etoh1[0] + etoh_liq = ctx.define_liquid( + name="Ethanol 80%", description="Fresh 80% Ethanol", display_color="#FF00FF" + ) + for well in etoh1: + well.load_liquid( + liquid=etoh_liq, volume=(etoh_vol * num_cols) + (0.1 * etoh_vol * num_cols) + ) + + etoh2 = reservoir.columns()[5] + etoh2_res = etoh2[0] + for well in etoh2: + well.load_liquid( + liquid=etoh_liq, volume=(etoh_vol * num_cols) + (0.1 * etoh_vol * num_cols) + ) + + waste1 = reservoir.columns()[6] + waste1_res = waste1[0] + + waste2 = reservoir.columns()[7] + waste2_res = waste2[0] + + def tiptrack(rack: int, reuse_col: Optional[int], reuse: bool = False) -> None: + """Tip Track.""" + global tt_50 + global tt_200 + global p50_racks_ondeck + global p200_racks_ondeck + global p50_racks_offdeck + global p200_racks_offdeck + global p50_rack_count + global p200_rack_count + + if rack == tip50: + if ( + tt_50 == 0 and not reuse + ): # If this is the first column of tip box and these aren't reused tips + ctx.comment("Troubleshoot") + if len(Available_on_deck_slots) > 0: + avail_slot = Available_on_deck_slots[0] + p50_rack_count += 1 + tt_50 += 12 + addtiprack = ctx.load_labware( + "opentrons_flex_96_tiprack_50ul", + avail_slot, + f"50 ul Tip Rack #{p50_rack_count}", + ) + ctx.comment( + f"Add 50 ul tip rack #{p50_rack_count} to slot {avail_slot}." + ) + Available_on_deck_slots.pop(0) + p50_racks_ondeck.append(addtiprack) + p50_racks_to_dump.append(addtiprack) + p50.tip_racks.append(addtiprack) + elif ( + len(Available_on_deck_slots) == 0 + and len(Available_off_deck_slots) > 0 + ): + p50_rack_count += 1 + tt_50 += 12 + addtiprack = ctx.load_labware( + "opentrons_flex_96_tiprack_50ul", + Available_off_deck_slots[0], + f"50 ul Tip Rack #{p50_rack_count}", + ) + Available_off_deck_slots.pop( + 0 + ) # Load rack into staging area slot to be moved on deck + ctx.comment(f"Adding 50 ul tip rack #{p50_rack_count}") + p50_racks_offdeck.append( + addtiprack + ) # used in TipSwap then deleted once it is moved + p50.tip_racks.append( + addtiprack + ) # lets pipette know it can use this rack now + TipSwap( + 50 + ) # Throw first tip box out and replace with a box from staging area + elif ( + len(Available_on_deck_slots) == 0 + and len(Available_off_deck_slots) == 0 + ): # If there are no tip racks on deck or in staging area to use + ctx.pause("Please place a new 50ul Tip Rack in slot A4") + p50_rack_count += 1 + tt_50 += 12 + addtiprack = ctx.load_labware( + "opentrons_flex_96_tiprack_50ul", + "A4", + f"50 ul Tip Rack #{p50_rack_count}", + ) + ctx.comment(f"Adding 50 ul tip rack #{p50_rack_count}") + p50_racks_offdeck.append( + addtiprack + ) # used in TipSwap, then deleted once it is moved + p50.tip_racks.append( + addtiprack + ) # lets pipette know it can use this rack now + TipSwap( + 50 + ) # Throw first tip box out and replace with a box from staging area + # Call where tips will actually be picked up + if reuse and REUSE_RSB_TIPS and reuse_col: + p50.pick_up_tip(tip50_reuse.wells()[8 * reuse_col]) + else: + tt_50 -= 1 + ctx.comment("Column " + str(12 - tt_50)) + ctx.comment( + "Available On Deck Slots:" + str(len(Available_on_deck_slots)) + ) + ctx.comment( + "Available Off Deck Slots:" + str(len(Available_off_deck_slots)) + ) + p50.pick_up_tip() + + if rack == tip200: + if ( + tt_200 == 0 and not reuse + ): # If this is the first column of tip box and these aren't reused tips + if len(Available_on_deck_slots) > 0: + avail_slot = Available_on_deck_slots[0] + p200_rack_count += 1 + tt_200 += 12 + addtiprack = ctx.load_labware( + "opentrons_flex_96_tiprack_200ul", + avail_slot, + f"200 ul Tip Rack #{p200_rack_count}", + ) + ctx.comment( + f"Adding 200 ul tip rack #{p200_rack_count} to slot {avail_slot}" + ) + Available_on_deck_slots.pop(0) + p200_racks_ondeck.append(addtiprack) + p200_racks_to_dump.append(addtiprack) + p200.tip_racks.append(addtiprack) + elif ( + len(Available_on_deck_slots) == 0 + and len(Available_off_deck_slots) > 0 + ): + p200_rack_count += 1 + tt_200 += 12 + addtiprack = ctx.load_labware( + "opentrons_flex_96_tiprack_200ul", + Available_off_deck_slots[0], + f"200 ul Tip Rack #{p200_rack_count}", + ) + Available_off_deck_slots.pop( + 0 + ) # Load rack into staging area slot to be moved on deck + ctx.comment(f"Adding 200 ul tip rack #{p200_rack_count}") + p200_racks_offdeck.append( + addtiprack + ) # used in TipSwap then deleted once it is moved + p200.tip_racks.append( + addtiprack + ) # lets pipette know it can use this rack now + TipSwap( + 200 + ) # Throw first tip box out and replace with a box from staging area + elif ( + len(Available_on_deck_slots) == 0 + and len(Available_off_deck_slots) == 0 + ): # If there are no tip racks on deck or in staging area to use + ctx.pause("Please place a new 200ul Tip Rack in slot B4") + p200_rack_count += 1 + tt_200 += 12 + addtiprack = ctx.load_labware( + "opentrons_flex_96_tiprack_200ul", + "B4", + f"200 ul Tip Rack #{p200_rack_count}", + ) + ctx.comment(f"Adding 200 ul tip rack #{p200_rack_count}") + p200_racks_offdeck.append( + addtiprack + ) # used in TipSwap, then deleted once it is moved + p200.tip_racks.append( + addtiprack + ) # lets pipette know it can use this rack now + TipSwap( + 200 + ) # Throw first tip box out and replace with a box from staging area + # Call where tips will actually be picked up + if reuse and REUSE_REMOVE_TIPS and reuse_col: + p200.pick_up_tip(tip200_reuse.wells()[8 * reuse_col]) + else: + tt_200 -= 1 + ctx.comment("Column " + str(12 - tt_200)) + ctx.comment( + "Available On Deck Slots:" + str(len(Available_on_deck_slots)) + ) + ctx.comment( + "Available Off Deck Slots:" + str(len(Available_off_deck_slots)) + ) + p200.pick_up_tip() + + def TipSwap(tipvol: int) -> None: + """Tip swap.""" + if tipvol == 50: + rack_to_dispose = p50_racks_to_dump[0] + rack_to_add = p50_racks_offdeck[0] + deck_slot = p50_racks_to_dump[0].parent + p50_racks_ondeck.append(rack_to_add) + p50_racks_to_dump.pop(0) + p50_racks_to_dump.append(rack_to_add) + p50_racks_ondeck.pop(0) + p50_racks_offdeck.pop(0) + + if tipvol == 200: + rack_to_dispose = p200_racks_to_dump[0] + rack_to_add = p200_racks_offdeck[0] + deck_slot = p200_racks_to_dump[0].parent + p200_racks_ondeck.append(rack_to_add) + p200_racks_to_dump.pop(0) + p200_racks_to_dump.append(rack_to_add) + p200_racks_ondeck.pop(0) + p200_racks_offdeck.pop(0) + + ctx.move_labware( + labware=rack_to_dispose, new_location=trash, use_gripper=USE_GRIPPER + ) + ctx.move_labware( + labware=rack_to_add, new_location=deck_slot, use_gripper=USE_GRIPPER + ) + ctx.comment( + f"Threw out: {rack_to_dispose} and placed {rack_to_add} to {deck_slot}" + ) + + def run_tag_profile( + unused_lids: List[Labware], used_lids: List[Labware] + ) -> Tuple[List[Labware], List[Labware]]: + """Run Tag Profile.""" + # Presetting Thermocycler Temps + ctx.comment( + "****Starting Fragmentation Profile (37C for 10 minutes with 100C lid)****" + ) + tc_mod.set_lid_temperature(100) + tc_mod.set_block_temperature(37) + + # Move Plate to TC + ctx.comment("****Moving Plate to Pre-Warmed TC Module Block****") + ctx.move_labware(sample_plate, tc_mod, use_gripper=USE_GRIPPER) + + if disposable_lid: + lid_on_plate, unused_lids, used_lids = helpers.use_disposable_lid_with_tc( + ctx, unused_lids, used_lids, sample_plate, tc_mod + ) + else: + tc_mod.close_lid() + tc_mod.set_block_temperature( + temperature=37, hold_time_minutes=Fragmentation_time, block_max_volume=50 + ) + tc_mod.open_lid() + + if disposable_lid: + if len(used_lids) <= 1: + ctx.move_labware(lid_on_plate, "C4", use_gripper=True) + else: + ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) + # #Move Plate to H-S + ctx.comment("****Moving Plate off of TC****") + + ctx.move_labware(sample_plate, "D1", use_gripper=USE_GRIPPER) + return unused_lids, used_lids + + def run_er_profile( + unused_lids: List[Labware], used_lids: List[Labware] + ) -> Tuple[List[Labware], List[Labware]]: + """End Repair Profile.""" + # Presetting Thermocycler Temps + ctx.comment( + "****Starting End Repair Profile (65C for 30 minutes with 100C lid)****" + ) + tc_mod.set_lid_temperature(100) + tc_mod.set_block_temperature(65) + + # Move Plate to TC + ctx.comment("****Moving Plate to Pre-Warmed TC Module Block****") + ctx.move_labware(sample_plate, tc_mod, use_gripper=USE_GRIPPER) + + if disposable_lid: + lid_on_plate, unused_lids, used_lids = helpers.use_disposable_lid_with_tc( + ctx, unused_lids, used_lids, sample_plate, tc_mod + ) + else: + tc_mod.close_lid() + tc_mod.set_block_temperature( + temperature=65, hold_time_minutes=30, block_max_volume=50 + ) + + tc_mod.deactivate_block() + tc_mod.open_lid() + + if disposable_lid: + # move lid + if len(used_lids) <= 1: + ctx.move_labware(lid_on_plate, "C4", use_gripper=True) + else: + ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) + # #Move Plate to H-S + ctx.comment("****Moving Plate off of TC****") + + ctx.move_labware(sample_plate, "D1", use_gripper=USE_GRIPPER) + return unused_lids, used_lids + + def run_ligation_profile( + unused_lids: List[Labware], used_lids: List[Labware] + ) -> Tuple[List[Labware], List[Labware]]: + """Run Ligation Profile.""" + # Presetting Thermocycler Temps + ctx.comment( + "****Starting Ligation Profile (20C for 15 minutes with 100C lid)****" + ) + tc_mod.set_lid_temperature(100) + tc_mod.set_block_temperature(20) + + # Move Plate to TC + ctx.comment("****Moving Plate to Pre-Warmed TC Module Block****") + + ctx.move_labware(sample_plate, tc_mod, use_gripper=USE_GRIPPER) + + if disposable_lid: + lid_on_plate, unused_lids, used_lids = helpers.use_disposable_lid_with_tc( + ctx, unused_lids, used_lids, sample_plate, tc_mod + ) + else: + tc_mod.close_lid() + tc_mod.set_block_temperature( + temperature=20, hold_time_minutes=ligation_tc_time, block_max_volume=50 + ) + + tc_mod.deactivate_block() + + tc_mod.open_lid() + # Move lid + tc_mod.open_lid() + if disposable_lid: + if len(used_lids) <= 1: + ctx.move_labware(lid_on_plate, "C4", use_gripper=True) + else: + ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) + + # #Move Plate to H-S + ctx.comment("****Moving Plate off of TC****") + + ctx.move_labware(sample_plate, "D1", use_gripper=USE_GRIPPER) + return unused_lids, used_lids + + def run_amplification_profile( + unused_lids: List[Labware], used_lids: List[Labware] + ) -> Tuple[List[Labware], List[Labware]]: + """Run Amplification Profile.""" + # Presetting Thermocycler Temps + ctx.comment( + "Amplification Profile (37C for 5 min, 50C for 5 min with 100C lid)" + ) + tc_mod.set_lid_temperature(100) + tc_mod.set_block_temperature(98) + + # Move Plate to TC + ctx.comment("****Moving Sample Plate onto TC****") + ctx.move_labware(sample_plate_2, tc_mod, use_gripper=USE_GRIPPER) + + if not dry_run: + tc_mod.set_lid_temperature(105) + if disposable_lid: + lid_on_plate, unused_lids, used_lids = helpers.use_disposable_lid_with_tc( + ctx, unused_lids, used_lids, sample_plate_2, tc_mod + ) + else: + tc_mod.close_lid() + if not dry_run: + profile_PCR_1: List[ThermocyclerStep] = [ + {"temperature": 98, "hold_time_seconds": 45} + ] + tc_mod.execute_profile( + steps=profile_PCR_1, repetitions=1, block_max_volume=50 + ) + profile_PCR_2: List[ThermocyclerStep] = [ + {"temperature": 98, "hold_time_seconds": 15}, + {"temperature": 60, "hold_time_seconds": 30}, + {"temperature": 72, "hold_time_seconds": 30}, + ] + tc_mod.execute_profile( + steps=profile_PCR_2, repetitions=PCRCYCLES, block_max_volume=50 + ) + profile_PCR_3: List[ThermocyclerStep] = [ + {"temperature": 72, "hold_time_minutes": 1} + ] + tc_mod.execute_profile( + steps=profile_PCR_3, repetitions=1, block_max_volume=50 + ) + tc_mod.set_block_temperature(4) + tc_mod.open_lid() + if disposable_lid: + if len(used_lids) <= 1: + ctx.move_labware(lid_on_plate, "C4", use_gripper=True) + else: + ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) + + # Move Sample Plate to H-S + ctx.comment("****Moving Sample Plate back to H-S****") + ctx.move_labware(sample_plate_2, "D1", use_gripper=USE_GRIPPER) + # get FLP plate out of the way + ctx.comment("****Moving FLP Plate back to TC****") + ctx.move_labware(FLP_plate, tc_mod, use_gripper=USE_GRIPPER) + return unused_lids, used_lids + + def mix_beads( + pip: InstrumentContext, res: Well, vol: int, reps: int, col: int + ) -> None: + """Mix beads function.""" + # Multiplier tells + mix_vol = (num_cols - col) * vol + if pip == p50: + if mix_vol > 50: + mix_vol = 50 + if pip == p200: + if mix_vol > 200: + mix_vol = 200 + + if res == bead_res: + width = res.width + else: + width = res.diameter + if width: + move = (width / 2) - 1 + + loc_center_a = res.bottom().move(types.Point(x=0, y=0, z=0.5)) + loc_center_d = res.bottom().move(types.Point(x=0, y=0, z=0.5)) + loc1 = res.bottom().move(types.Point(x=move, y=0, z=5)) + loc2 = res.bottom().move(types.Point(x=0, y=move, z=5)) + loc3 = res.bottom().move(types.Point(x=-move, y=0, z=5)) + loc4 = res.bottom().move(types.Point(x=0, y=-move, z=5)) + loc5 = res.bottom().move(types.Point(x=move / 2, y=move / 2, z=5)) + loc6 = res.bottom().move(types.Point(x=-move / 2, y=move / 2, z=5)) + loc7 = res.bottom().move(types.Point(x=-move / 2, y=-move / 2, z=5)) + loc8 = res.bottom().move(types.Point(x=move / 2, y=-move / 2, z=5)) + + loc = [loc_center_d, loc1, loc5, loc2, loc6, loc3, loc7, loc4, loc8] + + pip.aspirate( + mix_vol, res.bottom().move(types.Point(x=0, y=0, z=10)) + ) # Blow bubbles to start + pip.dispense(mix_vol, loc_center_d) + for x in range(reps): + pip.aspirate(mix_vol, loc_center_a) + pip.dispense(mix_vol, loc[x]) + pip.flow_rate.aspirate = 10 + pip.flow_rate.dispense = 10 + pip.aspirate(mix_vol, loc_center_a) + pip.dispense(mix_vol, loc_center_d) + pip.flow_rate.aspirate = 150 + pip.flow_rate.dispense = 150 + + def remove_supernatant(well: Well, vol: float, waste_: Well, column: int) -> None: + """Remove supernatant.""" + ctx.comment("-------Removing " + str(vol) + "ul of Supernatant-------") + p200.flow_rate.aspirate = 15 + num_trans = math.ceil(vol / 190) + vol_per_trans = vol / num_trans + for x in range(num_trans): + tiptrack(tip200, column, reuse=True if REUSE_REMOVE_TIPS else False) + p200.aspirate(vol_per_trans / 2, well.bottom(0.2)) + ctx.delay(seconds=1) + p200.aspirate(vol_per_trans / 2, well.bottom(0.2)) + p200.air_gap(10) + p200.dispense(p200.current_volume, waste_) + p200.air_gap(10) + if REUSE_REMOVE_TIPS: + p200.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + else: + if trash_tips: + p200.drop_tip() + ctx.comment("****Dropping Tip in Waste shoot****") + else: + p200.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + p200.flow_rate.aspirate = 150 + + def Fragmentation( + unused_lids: List[Labware], used_lids: List[Labware] + ) -> Tuple[List[Labware], List[Labware]]: + """Fragmentation Function.""" + ctx.comment("-------Starting Fragmentation-------") + + for i in range(num_cols): + + ctx.comment("Mixing and Transfering beads to column " + str(i + 1)) + + tiptrack(tip50, None, reuse=False) + p50.flow_rate.dispense = 15 + p50.aspirate(frag_vol, frag_res) + p50.dispense(p50.current_volume, samples[i]) + p50.flow_rate.dispense = 150 + for x in range(10 if not dry_run else 1): + if x == 9: + p50.flow_rate.aspirate = 15 + p50.flow_rate.dispense = 15 + p50.aspirate(frag_vol, samples[i].bottom(1)) + p50.dispense(p50.current_volume, samples[i].bottom(5)) + p50.flow_rate.aspirate = 150 + p50.flow_rate.dispense = 150 + if trash_tips: + p50.drop_tip() + ctx.comment("****Dropping Tip in Waste shoot****") + else: + p50.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + + unused_lids, used_lids = run_tag_profile( + unused_lids, used_lids + ) # Heats TC --> moves plate to TC --> TAG Profile --> removes plate from TC + return unused_lids, used_lids + + def end_repair( + unused_lids: List[Labware], used_lids: List[Labware] + ) -> Tuple[List[Labware], List[Labware]]: + """End Repair Function.""" + ctx.comment("-------Starting end_repair-------") + + for i in range(num_cols): + + ctx.comment( + "**** Mixing and Transfering beads to column " + str(i + 1) + " ****" + ) + + tiptrack(tip50, None, reuse=False) + p50.flow_rate.dispense = 15 + p50.aspirate(end_repair_vol, er_res) + p50.dispense(p50.current_volume, samples[i]) + p50.flow_rate.dispense = 150 + for x in range(10 if not dry_run else 1): + if x == 9: + p50.flow_rate.aspirate = 15 + p50.flow_rate.dispense = 15 + p50.aspirate(end_repair_vol, samples[i].bottom(1)) + p50.dispense(p50.current_volume, samples[i].bottom(5)) + p50.flow_rate.aspirate = 150 + p50.flow_rate.dispense = 150 + if trash_tips: + p50.drop_tip() + ctx.comment("****Dropping Tip in Waste shoot****") + else: + p50.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + + unused_lids, used_lids = run_er_profile( + unused_lids, used_lids + ) # Heats TC --> moves plate to TC --> TAG Profile --> removes plate from TC + return unused_lids, used_lids + + # Index Ligation + + def index_ligation( + unused_lids: List[Labware], used_lids: List[Labware] + ) -> Tuple[List[Labware], List[Labware]]: + """Index Ligation.""" + ctx.comment("-------Ligating Indexes-------") + ctx.comment("-------Adding and Mixing ELM-------") + for i in samples: + tiptrack(tip50, None, reuse=False) + p50.aspirate(ligation_vol, ligation_res) + p50.dispense(p50.current_volume, i) + for x in range(10 if not dry_run else 1): + if x == 9: + p50.flow_rate.aspirate = 75 + p50.flow_rate.dispense = 75 + p50.aspirate(ligation_vol - 10, i) + p50.dispense(p50.current_volume, i.bottom(8)) + p50.flow_rate.aspirate = 150 + p50.flow_rate.dispense = 150 + if trash_tips: + p50.drop_tip() + ctx.comment("****Dropping Tip in Waste shoot****") + else: + p50.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + + # Add and mix adapters + ctx.comment("-------Adding and Mixing Adapters-------") + for i_well, x_well in zip(samples, adapters): + tiptrack(tip50, None, reuse=False) + p50.aspirate(adapter_vol, x_well) + p50.dispense(p50.current_volume, i_well) + for y in range(10 if not dry_run else 1): + if y == 9: + p50.flow_rate.aspirate = 75 + p50.flow_rate.dispense = 75 + p50.aspirate(40, i_well) + p50.dispense(40, i_well.bottom(8)) + if trash_tips: + p50.drop_tip() + ctx.comment("****Dropping Tip in Waste shoot****") + else: + p50.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + + p50.flow_rate.aspirate = 150 + p50.flow_rate.dispense = 150 + + unused_lids, used_lids = run_ligation_profile(unused_lids, used_lids) + return unused_lids, used_lids + + def lib_cleanup() -> None: + """Litigation Clean up.""" + ctx.comment("-------Starting Cleanup-------") + ctx.comment("-------Adding and Mixing Cleanup Beads-------") + + # Move FLP plate off magnetic module if it's there + if FLP_plate.parent == magblock: + ctx.comment("****Moving FLP Plate off Magnetic Module****") + ctx.move_labware(FLP_plate, tc_mod, use_gripper=USE_GRIPPER) + + for x, i in enumerate(samples): + tiptrack(tip200, None, reuse=False) + mix_beads(p200, bead_res, bead_vol_1, 7 if x == 0 else 2, x) + p200.aspirate(bead_vol_1, bead_res) + p200.dispense(bead_vol_1, i) + mix_beads(p200, i, bead_vol_1, 7 if not dry_run else 1, num_cols - 1) + for x in range(10 if not dry_run else 1): + if x == 9: + p200.flow_rate.aspirate = 75 + p200.flow_rate.dispense = 75 + p200.aspirate(bead_vol_1, i) + p200.dispense(bead_vol_1, i.bottom(8)) + p200.flow_rate.aspirate = 150 + p200.flow_rate.dispense = 150 + if trash_tips: + p200.drop_tip() + ctx.comment("****Dropping Tip in Waste shoot****") + else: + p200.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + + ctx.delay( + minutes=bead_inc, + msg="Please wait " + + str(bead_inc) + + " minutes while samples incubate at RT.", + ) + + ctx.comment("****Moving Labware to Magnet for Pelleting****") + ctx.move_labware(sample_plate, magblock, use_gripper=USE_GRIPPER) + + ctx.delay(minutes=4.5, msg="Time for Pelleting") + + for col, i in enumerate(samples): + remove_supernatant(i, 130, waste1_res, col) + samp_list = samples + + # Wash 2 x with 80% Ethanol + p200.flow_rate.aspirate = 75 + p200.flow_rate.dispense = 75 + for y in range(2 if not dry_run else 1): + ctx.comment(f"-------Wash # {y+1} with Ethanol-------") + if y == 0: # First wash + this_res = etoh1_res + this_waste_res = waste1_res + else: # Second Wash + this_res = etoh2_res + this_waste_res = waste2_res + if REUSE_ETOH_TIPS: + tiptrack(tip200, None, reuse=False) + for i in samp_list: + if not REUSE_ETOH_TIPS: + tiptrack(tip200, None, reuse=False) + p200.aspirate(150, this_res) + p200.air_gap(10) + p200.dispense(p200.current_volume, i.top()) + ctx.delay(seconds=1) + p200.air_gap(10) + if not REUSE_ETOH_TIPS: + p200.drop_tip() if trash_tips else p200.return_tip() + + ctx.delay(seconds=10) + # Remove the ethanol wash + for x, i in enumerate(samp_list): + if REUSE_ETOH_TIPS: + if x != 0: + tiptrack(tip200, None, reuse=False) + if not REUSE_ETOH_TIPS: + tiptrack(tip200, None, reuse=False) + p200.aspirate(155, i) + p200.air_gap(10) + p200.dispense(p200.current_volume, this_waste_res) + ctx.delay(seconds=1) + p200.air_gap(10) + if trash_tips: + p200.drop_tip() + ctx.comment("****Dropping Tip in Waste shoot****") + else: + p200.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + + p200.flow_rate.aspirate = 150 + p200.flow_rate.dispense = 150 + + # Wash complete, move on to drying steps. + ctx.delay(minutes=2, msg="Allow 3 minutes for residual ethanol to dry") + + # Return Plate to H-S from Magnet + + ctx.comment("****Moving sample plate off of Magnet****") + ctx.move_labware(sample_plate, "D1", use_gripper=USE_GRIPPER) + + # Adding RSB and Mixing + + for col, i in enumerate(samp_list): + ctx.comment(f"****Adding RSB to Columns: {col+1}****") + tiptrack(tip50, col, reuse=True if REUSE_RSB_TIPS else False) + p50.aspirate(rsb_vol_1, rsb_res) + p50.air_gap(5) + p50.dispense(p50.current_volume, i) + for x in range(10 if not dry_run else 1): + if x == 9: + p50.flow_rate.aspirate = 15 + p50.flow_rate.dispense = 15 + p50.aspirate(15, i.bottom(1)) + p50.dispense(15, i.bottom(4)) + p50.flow_rate.aspirate = 100 + p50.flow_rate.dispense = 100 + p50.air_gap(5) + if REUSE_RSB_TIPS: + p50.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + else: + if trash_tips: + p50.drop_tip() + ctx.comment("****Dropping Tip in Waste shoot****") + else: + p50.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + + ctx.delay( + minutes=3, msg="Allow 3 minutes for incubation and liquid aggregation." + ) + + ctx.comment("****Move Samples to Magnet for Pelleting****") + ctx.move_labware(sample_plate, magblock, use_gripper=USE_GRIPPER) + + ctx.delay(minutes=2, msg="Please allow 2 minutes for beads to pellet.") + + p200.flow_rate.aspirate = 10 + for i_int, (s, e) in enumerate(zip(samp_list, samples_2)): + tiptrack(tip50, i_int, reuse=True if REUSE_RSB_TIPS else False) + p50.aspirate(elution_vol, s) + p50.air_gap(5) + p50.dispense(p50.current_volume, e.bottom(1), push_out=3) + p50.air_gap(5) + if trash_tips: + p50.drop_tip() + ctx.comment("****Dropping Tip in Waste shoot****") + else: + p50.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + + # move new sample plate to D1 or heatershaker + ctx.comment("****Moving sample plate off of Magnet****") + ctx.move_labware(sample_plate_2, "D1", use_gripper=USE_GRIPPER) + + # Keep Sample PLate 1 to B2 + ctx.comment("****Moving Sample_plate_1 Plate off magnet to B2****") + ctx.move_labware(sample_plate, "B2", use_gripper=USE_GRIPPER) + + ctx.comment("****Moving FLP Plate off TC****") + ctx.move_labware(FLP_plate, magblock, use_gripper=USE_GRIPPER) + + def lib_amplification( + unused_lids: List[Labware], used_lids: List[Labware] + ) -> Tuple[List[Labware], List[Labware]]: + """Library Amplification.""" + ctx.comment("-------Starting lib_amplification-------") + + for i in range(num_cols): + + ctx.comment( + "**** Mixing and Transfering beads to column " + str(i + 1) + " ****" + ) + + tiptrack(tip50, None, reuse=False) + mix_beads( + p50, amplification_res, amplification_vol, 7 if i == 0 else 2, i + ) # 5 reps for first mix in reservoir + p50.flow_rate.dispense = 15 + p50.aspirate(amplification_vol, amplification_res) + p50.dispense(p50.current_volume, samples_2[i]) + p50.flow_rate.dispense = 150 + for x in range(10 if not dry_run else 1): + if x == 9: + p50.flow_rate.aspirate = 15 + p50.flow_rate.dispense = 15 + p50.aspirate(amplification_vol, samples_2[i].bottom(1)) + p50.dispense(p50.current_volume, samples_2[i].bottom(5)) + p50.flow_rate.aspirate = 150 + p50.flow_rate.dispense = 150 + if trash_tips: + p50.drop_tip() + ctx.comment("****Dropping Tip in Waste shoot****") + else: + p50.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + + unused_lids, used_lids = run_amplification_profile( + unused_lids, used_lids + ) # moves plate to TC --> TAG Profile --> removes plate from TC + return unused_lids, used_lids + + def lib_cleanup_2() -> None: + """Final Library Clean up.""" + ctx.comment("-------Starting Cleanup-------") + ctx.comment("-------Adding and Mixing Cleanup Beads-------") + for x, i in enumerate(samples_2): + tiptrack(tip200, None, reuse=False) + mix_beads(p200, bead_res, bead_vol_2, 7 if x == 0 else 2, x) + p200.aspirate(bead_vol_2, bead_res) + p200.dispense(bead_vol_2, i) + mix_beads(p200, i, bead_vol_2, 7 if not dry_run else 1, num_cols - 1) + for x in range(10 if not dry_run else 1): + if x == 9: + p200.flow_rate.aspirate = 75 + p200.flow_rate.dispense = 75 + p200.aspirate(bead_vol_2, i) + p200.dispense(bead_vol_2, i.bottom(8)) + p200.flow_rate.aspirate = 150 + p200.flow_rate.dispense = 150 + if trash_tips: + p200.drop_tip() + ctx.comment("****Dropping Tip in Waste shoot****") + else: + p200.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + + ctx.delay( + minutes=bead_inc, + msg="Please wait " + + str(bead_inc) + + " minutes while samples incubate at RT.", + ) + + ctx.comment("****Moving Labware to Magnet for Pelleting****") + ctx.move_labware(sample_plate_2, magblock, use_gripper=USE_GRIPPER) + + ctx.delay(minutes=4.5, msg="Time for Pelleting") + + for col, i in enumerate(samples_2): + remove_supernatant(i, 130, waste1_res, col) + samp_list_2 = samples_2 + # Wash 2 x with 80% Ethanol + + p200.flow_rate.aspirate = 75 + p200.flow_rate.dispense = 75 + for y in range(2 if not dry_run else 1): + ctx.comment(f"-------Wash # {y+1} with Ethanol-------") + if y == 0: # First wash + this_res = etoh1_res + this_waste_res = waste1_res + else: # Second Wash + this_res = etoh2_res + this_waste_res = waste2_res + if REUSE_ETOH_TIPS: + tiptrack(tip200, None, reuse=False) + for i in samp_list_2: + if not REUSE_ETOH_TIPS: + tiptrack(tip200, None, reuse=False) + p200.aspirate(150, this_res) + p200.air_gap(10) + p200.dispense(p200.current_volume, i.top()) + ctx.delay(seconds=1) + p200.air_gap(10) + if not REUSE_ETOH_TIPS: + p200.drop_tip() if trash_tips else p200.return_tip() + + ctx.delay(seconds=10) + # Remove the ethanol wash + for x, i in enumerate(samp_list_2): + if REUSE_ETOH_TIPS: + if x != 0: + tiptrack(tip200, None, reuse=False) + if not REUSE_ETOH_TIPS: + tiptrack(tip200, None, reuse=False) + p200.aspirate(155, i) + p200.air_gap(10) + p200.dispense(p200.current_volume, this_waste_res) + ctx.delay(seconds=1) + p200.air_gap(10) + if trash_tips: + p200.drop_tip() + ctx.comment("****Dropping Tip in Waste shoot****") + else: + p200.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + + p200.flow_rate.aspirate = 150 + p200.flow_rate.dispense = 150 + + # Washes Complete, Move on to Drying Steps + + ctx.delay(minutes=3, msg="Allow 3 minutes for residual ethanol to dry") + + ctx.comment("****Moving sample plate off of Magnet****") + ctx.move_labware(sample_plate_2, "D1", use_gripper=USE_GRIPPER) + + # Adding RSB and Mixing + + for col, i in enumerate(samp_list_2): + ctx.comment(f"****Adding RSB to Columns: {col+1}****") + tiptrack(tip50, col, reuse=True if REUSE_RSB_TIPS else False) + p50.aspirate(rsb_vol_2, rsb_res) + p50.air_gap(5) + p50.dispense(p50.current_volume, i) + for x in range(10 if not dry_run else 1): + if x == 9: + p50.flow_rate.aspirate = 15 + p50.flow_rate.dispense = 15 + p50.aspirate(15, i.bottom(1)) + p50.dispense(15, i.bottom(4)) + p50.flow_rate.aspirate = 100 + p50.flow_rate.dispense = 100 + p50.air_gap(5) + if REUSE_RSB_TIPS: + p50.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + else: + if trash_tips: + p50.drop_tip() + ctx.comment("****Dropping Tip in Waste shoot****") + else: + p50.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + + ctx.delay( + minutes=3, msg="Allow 3 minutes for incubation and liquid aggregation." + ) + + ctx.comment("****Move Samples to Magnet for Pelleting****") + ctx.move_labware(sample_plate_2, magblock, use_gripper=USE_GRIPPER) + + ctx.delay(minutes=2, msg="Please allow 2 minutes for beads to pellet.") + + p200.flow_rate.aspirate = 10 + for i_int, (s, e) in enumerate(zip(samp_list_2, samples_flp)): + tiptrack(tip50, i_int, reuse=True if REUSE_RSB_TIPS else False) + p50.aspirate(elution_vol_2, s) + p50.air_gap(5) + p50.dispense(p50.current_volume, e.bottom(1), push_out=3) + p50.air_gap(5) + if trash_tips: + p50.drop_tip() + ctx.comment("****Dropping Tip in Waste shoot****") + else: + p50.return_tip() + ctx.comment("****Dropping Tip Back in Tip Box****") + + # Set Block Temp for Final Plate + tc_mod.set_block_temperature(4) + + unused_lids, used_lids = Fragmentation(unused_lids, used_lids) + unused_lids, used_lids = end_repair(unused_lids, used_lids) + unused_lids, used_lids = index_ligation(unused_lids, used_lids) + lib_cleanup() + unused_lids, used_lids = lib_amplification(unused_lids, used_lids) + lib_cleanup_2() diff --git a/abr-testing/abr_testing/protocols/api 2.20/5_96ch complex protocol with single tip Pick Up.py b/abr-testing/abr_testing/protocols/api 2.20/5_96ch complex protocol with single tip Pick Up.py new file mode 100644 index 00000000000..53b68503202 --- /dev/null +++ b/abr-testing/abr_testing/protocols/api 2.20/5_96ch complex protocol with single tip Pick Up.py @@ -0,0 +1,424 @@ +"""96 ch Test Single Tip and Gripper Moves.""" +from opentrons.protocol_api import ( + ALL, + SINGLE, + ParameterContext, + ProtocolContext, + Labware, +) +from opentrons.protocol_api.module_contexts import ( + HeaterShakerContext, + MagneticBlockContext, + ThermocyclerContext, + TemperatureModuleContext, +) +from abr_testing.protocols import helpers +from typing import List +from opentrons.hardware_control.modules.types import ThermocyclerStep + +metadata = { + "protocolName": "96ch protocol with modules gripper moves and SINGLE tip pickup", + "author": "Derek Maggio ", +} + +requirements = { + "robotType": "OT-3", + "apiLevel": "2.20", +} + + +# prefer to move off deck, instead of waste chute disposal, if possible +PREFER_MOVE_OFF_DECK = False + + +PCR_PLATE_96_NAME = "armadillo_96_wellplate_200ul_pcr_full_skirt" +RESERVOIR_NAME = "nest_96_wellplate_2ml_deep" +TIPRACK_96_ADAPTER_NAME = "opentrons_flex_96_tiprack_adapter" +PIPETTE_96_CHANNEL_NAME = "flex_96channel_1000" + +USING_GRIPPER = True +RESET_AFTER_EACH_MOVE = True + + +def add_parameters(parameters: ParameterContext) -> None: + """Parameters.""" + helpers.create_tip_size_parameter(parameters) + helpers.create_dot_bottom_parameter(parameters) + helpers.create_disposable_lid_parameter(parameters) + + +def run(ctx: ProtocolContext) -> None: + """Protocol.""" + b = ctx.params.dot_bottom # type: ignore[attr-defined] + TIPRACK_96_NAME = ctx.params.tip_size # type: ignore[attr-defined] + disposable_lid = ctx.params.disposable_lid # type: ignore[attr-defined] + + waste_chute = ctx.load_waste_chute() + + thermocycler: ThermocyclerContext = ctx.load_module(helpers.tc_str) # type: ignore[assignment] + mag: MagneticBlockContext = ctx.load_module(helpers.mag_str, "A3") # type: ignore[assignment] + h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] + temperature_module: TemperatureModuleContext = ctx.load_module( + helpers.temp_str, "C1" + ) # type: ignore[assignment] + if disposable_lid: + unused_lids = helpers.load_disposable_lids(ctx, 3, "A4") + used_lids: List[Labware] = [] + thermocycler.open_lid() + h_s.open_labware_latch() + + temperature_module_adapter = temperature_module.load_adapter( + helpers.temp_adapter_str + ) + h_s_adapter = h_s.load_adapter(helpers.hs_adapter_str) + + adapters = [temperature_module_adapter, h_s_adapter] + + source_reservoir = ctx.load_labware(RESERVOIR_NAME, "D2") + dest_pcr_plate = ctx.load_labware(PCR_PLATE_96_NAME, "C2") + + tip_rack_1 = ctx.load_labware( + TIPRACK_96_NAME, "A2", adapter=TIPRACK_96_ADAPTER_NAME + ) + tip_rack_adapter = tip_rack_1.parent + + tip_rack_2 = ctx.load_labware(TIPRACK_96_NAME, "C3") + tip_rack_3 = ctx.load_labware(TIPRACK_96_NAME, "C4") + + tip_racks = [ + tip_rack_1, + tip_rack_2, + tip_rack_3, + ] + + pipette_96_channel = ctx.load_instrument( + PIPETTE_96_CHANNEL_NAME, + mount="left", + tip_racks=tip_racks, + liquid_presence_detection=True, + ) + + water = ctx.define_liquid(name="water", description="H₂O", display_color="#42AB2D") + source_reservoir.wells_by_name()["A1"].load_liquid(liquid=water, volume=29000) + + def run_moves( + labware: Labware, move_sequences: List, reset_location: str, use_gripper: bool + ) -> None: + """Perform a series of moves for a given labware using specified move sequences. + + Will perform 2 versions of the moves: + 1.Moves to each location, resetting to the reset location after each move. + 2.Moves to each location, resetting to the reset location after all moves. + """ + + def move_to_locations( + labware_to_move: Labware, + move_locations: List, + reset_after_each_move: bool, + use_gripper: bool, + reset_location: str, + ) -> None: + """Move labware to specific destinations.""" + + def reset_labware() -> None: + """Reset the labware to the reset location.""" + ctx.move_labware( + labware_to_move, reset_location, use_gripper=use_gripper + ) + + if len(move_locations) == 0: + return + + for location in move_locations: + ctx.move_labware(labware_to_move, location, use_gripper=use_gripper) + + if reset_after_each_move: + reset_labware() + + if not reset_after_each_move: + reset_labware() + + for move_sequence in move_sequences: + move_to_locations( + labware, + move_sequence, + RESET_AFTER_EACH_MOVE, + use_gripper, + reset_location, + ) + move_to_locations( + labware, + move_sequence, + not RESET_AFTER_EACH_MOVE, + use_gripper, + reset_location, + ) + + def test_gripper_moves() -> None: + """Function to test the movement of the gripper in various locations.""" + + def deck_moves(labware: Labware, reset_location: str) -> None: + """Function to perform the movement of labware.""" + deck_move_sequence = [ + ["B2"], # Deck Moves + ["C3"], # Staging Area Slot 3 Moves + ["C4", "D4"], # Staging Area Slot 4 Moves + [ + thermocycler, + temperature_module_adapter, + h_s_adapter, + mag, + ], # Module Moves + ] + + run_moves(labware, deck_move_sequence, reset_location, USING_GRIPPER) + + def staging_area_slot_3_moves(labware: Labware, reset_location: str) -> None: + """Function to perform the movement of labware, starting w/ staging area slot 3.""" + staging_area_slot_3_move_sequence = [ + ["B2", "C2"], # Deck Moves + [], # Don't have Staging Area Slot 3 open + ["C4", "D4"], # Staging Area Slot 4 Moves + [ + thermocycler, + temperature_module_adapter, + h_s_adapter, + mag, + ], # Module Moves + ] + + run_moves( + labware, + staging_area_slot_3_move_sequence, + reset_location, + USING_GRIPPER, + ) + + def staging_area_slot_4_moves(labware: Labware, reset_location: str) -> None: + """Function to perform the movement of labware, starting with staging area slot 4.""" + staging_area_slot_4_move_sequence = [ + ["C2", "B2"], # Deck Moves + ["C3"], # Staging Area Slot 3 Moves + ["C4"], # Staging Area Slot 4 Moves + [ + thermocycler, + temperature_module_adapter, + h_s_adapter, + mag, + ], # Module Moves + ] + + run_moves( + labware, + staging_area_slot_4_move_sequence, + reset_location, + USING_GRIPPER, + ) + + def module_moves(labware: Labware, module_locations: List) -> None: + """Function to perform the movement of labware, starting on a module.""" + module_move_sequence = [ + ["C2", "B2"], # Deck Moves + ["C3"], # Staging Area Slot 3 Moves + ["C4", "D4"], # Staging Area Slot 4 Moves + ] + + for module_starting_location in module_locations: + labware_move_to_locations = module_locations.copy() + labware_move_to_locations.remove(module_starting_location) + all_sequences = module_move_sequence.copy() + all_sequences.append(labware_move_to_locations) + ctx.move_labware( + labware, module_starting_location, use_gripper=USING_GRIPPER + ) + run_moves( + labware, all_sequences, module_starting_location, USING_GRIPPER + ) + + DECK_MOVE_RESET_LOCATION = "C2" + STAGING_AREA_SLOT_3_RESET_LOCATION = "C3" + STAGING_AREA_SLOT_4_RESET_LOCATION = "D4" + + deck_moves(dest_pcr_plate, DECK_MOVE_RESET_LOCATION) + + ctx.move_labware( + dest_pcr_plate, + STAGING_AREA_SLOT_3_RESET_LOCATION, + use_gripper=USING_GRIPPER, + ) + staging_area_slot_3_moves(dest_pcr_plate, STAGING_AREA_SLOT_3_RESET_LOCATION) + + ctx.move_labware( + dest_pcr_plate, + STAGING_AREA_SLOT_4_RESET_LOCATION, + use_gripper=USING_GRIPPER, + ) + staging_area_slot_4_moves(dest_pcr_plate, STAGING_AREA_SLOT_4_RESET_LOCATION) + + module_locations = [thermocycler, mag] + adapters + module_moves(dest_pcr_plate, module_locations) + ctx.move_labware(dest_pcr_plate, thermocycler, use_gripper=USING_GRIPPER) + + def test_manual_moves() -> None: + """Test manual moves.""" + ctx.move_labware(source_reservoir, "D4", use_gripper=USING_GRIPPER) + + def test_pipetting() -> None: + """Test pipetting.""" + + def test_single_tip_pickup_usage() -> None: + """Test Single Tip Pick Up.""" + pipette_96_channel.configure_nozzle_layout(style=SINGLE, start="H12") + pipette_96_channel.liquid_presence_detection = True + tip_count = 0 # Tip counter to ensure proper tip usage + rows = ["A", "B", "C", "D", "E", "F", "G", "H"] # 8 rows + columns = range(1, 13) # 12 columns + for row in rows: + for col in columns: + well_position = f"{row}{col}" + pipette_96_channel.pick_up_tip(tip_rack_2) + + pipette_96_channel.aspirate(5, source_reservoir[well_position]) + pipette_96_channel.touch_tip() + + pipette_96_channel.dispense( + 5, dest_pcr_plate[well_position].bottom(b) + ) + pipette_96_channel.drop_tip() + tip_count += 1 + # leave this dropping in waste chute, do not use get_disposal_preference + # want to test partial drop + ctx.move_labware(tip_rack_2, waste_chute, use_gripper=USING_GRIPPER) + + def test_full_tip_rack_usage() -> None: + """Full Tip Pick Up.""" + pipette_96_channel.configure_nozzle_layout(style=ALL, start="A1") + pipette_96_channel.liquid_presence_detection = True + pipette_96_channel.pick_up_tip(tip_rack_1["A1"]) + + pipette_96_channel.aspirate(5, source_reservoir["A1"]) + pipette_96_channel.touch_tip() + + pipette_96_channel.liquid_presence_detection = False + pipette_96_channel.air_gap(height=30) + pipette_96_channel.blow_out(waste_chute) + + pipette_96_channel.aspirate(5, source_reservoir["A1"]) + pipette_96_channel.touch_tip() + + pipette_96_channel.air_gap(height=30) + pipette_96_channel.blow_out() + + pipette_96_channel.aspirate(10, source_reservoir["A1"]) + pipette_96_channel.touch_tip() + + pipette_96_channel.dispense(10, dest_pcr_plate["A1"].bottom(b)) + pipette_96_channel.mix(repetitions=5, volume=15) + pipette_96_channel.return_tip() + + ctx.move_labware(tip_rack_1, waste_chute, use_gripper=USING_GRIPPER) + ctx.move_labware(tip_rack_3, tip_rack_adapter, use_gripper=USING_GRIPPER) + + pipette_96_channel.pick_up_tip(tip_rack_3["A1"]) + pipette_96_channel.transfer( + volume=10, + source=source_reservoir["A1"], + dest=dest_pcr_plate["A1"], + new_tip="never", + touch_tip=True, + blow_out=True, + blowout_location="trash", + mix_before=(3, 5), + mix_after=(1, 5), + ) + pipette_96_channel.return_tip() + + ctx.move_labware(tip_rack_3, waste_chute, use_gripper=USING_GRIPPER) + + test_single_tip_pickup_usage() + test_full_tip_rack_usage() + + def test_module_usage(unused_lids: List[Labware], used_lids: List[Labware]) -> None: + """Test Module Use.""" + + def test_thermocycler( + unused_lids: List[Labware], used_lids: List[Labware] + ) -> None: + if disposable_lid: + ( + lid_on_plate, + unused_lids, + used_lids, + ) = helpers.use_disposable_lid_with_tc( + ctx, unused_lids, used_lids, dest_pcr_plate, thermocycler + ) + thermocycler.set_block_temperature(4) + thermocycler.set_lid_temperature(105) + # Close lid + thermocycler.close_lid() + # hold at 95° for 3 minutes + profile_TAG: List[ThermocyclerStep] = [ + {"temperature": 95, "hold_time_minutes": 3} + ] + thermocycler.execute_profile( + steps=profile_TAG, repetitions=1, block_max_volume=50 + ) + # 30x cycles of: 70° for 30s 72° for 30s 95° for 10s + profile_TAG2: List[ThermocyclerStep] = [ + {"temperature": 70, "hold_time_seconds": 30}, + {"temperature": 72, "hold_time_seconds": 30}, + {"temperature": 95, "hold_time_seconds": 10}, + ] + thermocycler.execute_profile( + steps=profile_TAG2, repetitions=30, block_max_volume=50 + ) + # hold at 72° for 5min + profile_TAG3: List[ThermocyclerStep] = [ + {"temperature": 72, "hold_time_minutes": 5} + ] + thermocycler.execute_profile( + steps=profile_TAG3, repetitions=1, block_max_volume=50 + ) + # # Cool to 4° + thermocycler.set_block_temperature(4) + thermocycler.set_lid_temperature(105) + # Open lid + thermocycler.open_lid() + if disposable_lid: + if len(used_lids) <= 1: + ctx.move_labware(lid_on_plate, "B3", use_gripper=True) + else: + ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) + thermocycler.deactivate() + + def test_h_s() -> None: + """Tests heatershaker.""" + h_s.open_labware_latch() + h_s.close_labware_latch() + + h_s.set_target_temperature(75.0) + h_s.set_and_wait_for_shake_speed(1000) + h_s.wait_for_temperature() + + h_s.deactivate_heater() + h_s.deactivate_shaker() + + def test_temperature_module() -> None: + """Tests temperature module.""" + temperature_module.set_temperature(80) + temperature_module.set_temperature(10) + temperature_module.deactivate() + + def test_mag() -> None: + """Tests magnetic block.""" + pass + + test_thermocycler(unused_lids, used_lids) + test_h_s() + test_temperature_module() + test_mag() + + test_pipetting() + test_gripper_moves() + test_module_usage(unused_lids, used_lids) + test_manual_moves() diff --git a/abr-testing/abr_testing/protocols/api 2.20/7_HDQ_DNA_Bacteria_Flex.py b/abr-testing/abr_testing/protocols/api 2.20/7_HDQ_DNA_Bacteria_Flex.py new file mode 100644 index 00000000000..7475eb11a34 --- /dev/null +++ b/abr-testing/abr_testing/protocols/api 2.20/7_HDQ_DNA_Bacteria_Flex.py @@ -0,0 +1,561 @@ +"""Omega HDQ DNA Extraction: Bacteria - Tissue Protocol.""" +from abr_testing.protocols import helpers +import math +from opentrons import types +from opentrons.protocol_api import ( + ProtocolContext, + Well, + ParameterContext, + InstrumentContext, +) +import numpy as np +from opentrons.protocol_api.module_contexts import ( + HeaterShakerContext, + TemperatureModuleContext, + MagneticBlockContext, +) +from typing import List, Union + +metadata = { + "author": "Zach Galluzzo ", + "protocolName": "Omega HDQ DNA Extraction: Bacteria- Tissue Protocol", +} + +requirements = { + "robotType": "OT-3", + "apiLevel": "2.20", +} +""" +Slot A1: Tips 1000 +Slot A2: Tips 1000 +Slot A3: Temperature module (gen2) with 96 well PCR block and Armadillo 96 well PCR Plate +Slot B1: Tips 1000 +Slot B2: +Slot B3: Nest 1 Well Reservoir +Slot C1: Magblock +Slot C2: +Slot C3: +Slot D1: H-S with Nest 96 Well Deep well and DW Adapter +Slot D2: Nest 12 well 15 ml Reservoir +Slot D3: Trash + +Reservoir 1: +Wells 1-2 - 9,900 ul +Well 3 - 14,310 ul +Wells 4-12 - 11,400 ul +""" + +whichwash = 1 +sample_max = 48 +tip1k = 0 +drop_count = 0 +waste_vol = 0 + + +def add_parameters(parameters: ParameterContext) -> None: + """Define Parameters.""" + helpers.create_pipette_mount_parameter(parameters) + helpers.create_hs_speed_parameter(parameters) + helpers.create_dot_bottom_parameter(parameters) + + +def run(ctx: ProtocolContext) -> None: + """Protocol.""" + heater_shaker_speed = ctx.params.heater_shaker_speed # type: ignore[attr-defined] + mount = ctx.params.pipette_mount # type: ignore[attr-defined] + dot_bottom = ctx.params.dot_bottom # type: ignore[attr-defined] + dry_run = False + TIP_TRASH = False + res_type = "nest_12_reservoir_22ml" + + num_samples = 8 + wash1_vol = 600 + wash2_vol = 600 + wash3_vol = 600 + AL_vol = 230 + sample_vol = 180 + bind_vol = 320 + elution_vol = 100 + + # Protocol Parameters + deepwell_type = "nest_96_wellplate_2ml_deep" + res_type = "nest_12_reservoir_15ml" + if not dry_run: + settling_time = 2.0 + A_lysis_time_1 = 15.0 + A_lysis_time_2 = 10.0 + bind_time = 10.0 + elute_wash_time = 5.0 + else: + settling_time = ( + elute_wash_time + ) = A_lysis_time_1 = A_lysis_time_2 = bind_time = 0.25 + PK_vol = bead_vol = 20 + AL_total_vol = AL_vol + PK_vol + starting_vol = AL_vol + sample_vol + binding_buffer_vol = bind_vol + bead_vol + + ctx.load_trash_bin("A3") + h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] + h_s_adapter = h_s.load_adapter("opentrons_96_deep_well_adapter") + sample_plate = h_s_adapter.load_labware(deepwell_type, "Sample Plate") + h_s.close_labware_latch() + temp: TemperatureModuleContext = ctx.load_module( + helpers.temp_str, "D3" + ) # type: ignore[assignment] + temp_block = temp.load_adapter("opentrons_96_well_aluminum_block") + elutionplate = temp_block.load_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", "Elution Plate" + ) + magnetic_block: MagneticBlockContext = ctx.load_module( + helpers.mag_str, "C1" + ) # type: ignore[assignment] + waste = ( + ctx.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") + .wells()[0] + .top() + ) + res1 = ctx.load_labware(res_type, "D2", "reagent reservoir 1") + num_cols = math.ceil(num_samples / 8) + + # Load tips and combine all similar boxes + tips1000 = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "A1", "Tips 1") + tips1001 = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "A2", "Tips 2") + tips1002 = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "B1", "Tips 3") + tips = [*tips1000.wells()[num_samples:96], *tips1001.wells(), *tips1002.wells()] + tips_sn = tips1000.wells()[:num_samples] + + # load instruments + m1000 = ctx.load_instrument("flex_8channel_1000", mount) + + """ + Here is where you can define the locations of your reagents. + """ + binding_buffer = res1.wells()[:2] + AL = res1.wells()[2] + wash1 = res1.wells()[3:6] + wash2 = res1.wells()[6:9] + wash3 = res1.wells()[9:] + + samples_m = sample_plate.rows()[0][:num_cols] + elution_samples_m = elutionplate.rows()[0][:num_cols] + + colors = helpers.liquid_colors + + # Begin with assigning plate wells before reservoir wells + samps = ctx.define_liquid( + name="Samples", description="Samples", display_color="#00FF00" + ) + elution_samps = ctx.define_liquid( + name="Elution Buffer", description="Elution Buffer", display_color="#FFA500" + ) + + for well_s in sample_plate.wells()[:num_samples]: + well_s.load_liquid(liquid=samps, volume=sample_vol) + + for well_e in elutionplate.wells()[:num_samples]: + well_e.load_liquid(liquid=elution_samps, volume=elution_vol) + + # Start defining reservoir wells + locations: List[Union[List[Well], Well]] = [ + AL, + AL, + binding_buffer, + binding_buffer, + wash1, + wash2, + wash3, + ] + vols = [AL_vol, PK_vol, bead_vol, bind_vol, wash1_vol, wash2_vol, wash3_vol] + liquids = ["AL Lysis", "PK", "Beads", "Binding", "Wash 1", "Wash 2", "Wash 3"] + + delete = len(colors) - len(liquids) + + if delete >= 1: + for i in range(delete): + colors.pop(-1) + + def add_liquid( + liq_type: str, wells: Union[Well, List[Well]], color: str, vol: float + ) -> None: + """Assigns colored liquid to wells based on type and location.""" + total_samples = math.ceil(num_samples / 8) * 8 + + # Calculate extra sample volume based on liquid type + extra_samples = math.ceil( + 1500 + / (AL_vol if liq_type == "PK" else bind_vol if liq_type == "Beads" else vol) + ) + + # Define liquid + liquid = ctx.define_liquid( + name=liq_type, description=liq_type, display_color=color + ) + + # Assign liquid to each well + if isinstance(wells, list): + samples_per_well = [sample_max // len(wells)] * ( + total_samples // (sample_max // len(wells)) + ) + remainder = total_samples % (sample_max // len(wells)) + + if remainder: + samples_per_well.append(remainder) + + for sample_count, well in zip(samples_per_well, wells): + well.load_liquid( + liquid=liquid, volume=vol * (sample_count + extra_samples) + ) + else: + wells.load_liquid( + liquid=liquid, volume=vol * (total_samples + extra_samples) + ) + + # Apply function for each liquid configuration + for liq, well, color, vol in zip(liquids, locations, colors, vols): + add_liquid(liq, well, color, vol) + + m1000.flow_rate.aspirate = 300 + m1000.flow_rate.dispense = 300 + m1000.flow_rate.blow_out = 300 + + def tiptrack(tipbox: List[Well]) -> None: + """Track Tips.""" + global tip1k + global drop_count + if tipbox == tips: + m1000.pick_up_tip(tipbox[int(tip1k)]) + tip1k = tip1k + 8 + drop_count = drop_count + 8 + if drop_count >= 150: + drop_count = 0 + ctx.pause("Empty Waste Bin.") + + def remove_supernatant(vol: float) -> None: + """Remove supernatants.""" + ctx.comment("-----Removing Supernatant-----") + m1000.flow_rate.aspirate = 150 + num_trans = math.ceil(vol / 980) + vol_per_trans = vol / num_trans + + for i, m in enumerate(samples_m): + m1000.pick_up_tip(tips_sn[8 * i]) + loc = m.bottom(dot_bottom) + for _ in range(num_trans): + if m1000.current_volume > 0: + # void air gap if necessary + m1000.dispense(m1000.current_volume, m.top()) + m1000.move_to(m.center()) + m1000.transfer(vol_per_trans, loc, waste, new_tip="never", air_gap=20) + m1000.blow_out(waste) + m1000.air_gap(20) + m1000.drop_tip(tips_sn[8 * i]) if TIP_TRASH else m1000.return_tip() + m1000.flow_rate.aspirate = 300 + helpers.move_labware_to_hs(ctx, sample_plate, h_s, h_s_adapter) + + def bead_mixing( + well: Well, pip: InstrumentContext, mvol: float, reps: int = 8 + ) -> None: + """Bead Mixing. + + 'mixing' will mix liquid that contains beads. This will be done by + aspirating from the bottom of the well and dispensing from the top as to + mix the beads with the other liquids as much as possible. Aspiration and + dispensing will also be reversed for a short to to ensure maximal mixing. + param well: The current well that the mixing will occur in. + param pip: The pipet that is currently attached/ being used. + param mvol: The volume that is transferred before the mixing steps. + param reps: The number of mix repetitions that should occur. Note~ + During each mix rep, there are 2 cycles of aspirating from bottom, + dispensing at the top and 2 cycles of aspirating from middle, + dispensing at the bottom + """ + center = well.top().move(types.Point(x=0, y=0, z=5)) + aspbot = well.bottom().move(types.Point(x=0, y=2, z=1)) + asptop = well.bottom().move(types.Point(x=0, y=-2, z=2.5)) + disbot = well.bottom().move(types.Point(x=0, y=1.5, z=3)) + distop = well.top().move(types.Point(x=0, y=1.5, z=0)) + + if mvol > 1000: + mvol = 1000 + + vol = mvol * 0.9 + + pip.flow_rate.aspirate = 500 + pip.flow_rate.dispense = 500 + + pip.move_to(center) + for _ in range(reps): + pip.aspirate(vol, aspbot) + pip.dispense(vol, distop) + pip.aspirate(vol, asptop) + pip.dispense(vol, disbot) + if _ == reps - 1: + pip.flow_rate.aspirate = 150 + pip.flow_rate.dispense = 100 + pip.aspirate(vol, aspbot) + pip.dispense(vol, aspbot) + + pip.flow_rate.aspirate = 300 + pip.flow_rate.dispense = 300 + + def mixing(well: Well, pip: InstrumentContext, mvol: float, reps: int = 8) -> None: + """Mixing. + + 'mixing' will mix liquid that contains beads. This will be done by + aspirating from the bottom of the well and dispensing from the top as to + mix the beads with the other liquids as much as possible. Aspiration and + dispensing will also be reversed for a short to to ensure maximal mixing. + param well: The current well that the mixing will occur in. + param pip: The pipet that is currently attached/ being used. + param mvol: The volume that is transferred before the mixing steps. + param reps: The number of mix repetitions that should occur. Note~ + During each mix rep, there are 2 cycles of aspirating from bottom, + dispensing at the top and 2 cycles of aspirating from middle, + dispensing at the bottom + """ + center = well.top(5) + asp = well.bottom(1) + disp = well.top(-8) + + if mvol > 1000: + mvol = 1000 + + vol = mvol * 0.9 + + pip.flow_rate.aspirate = 500 + pip.flow_rate.dispense = 500 + + pip.move_to(center) + for _ in range(reps): + pip.aspirate(vol, asp) + pip.dispense(vol, disp) + pip.aspirate(vol, asp) + pip.dispense(vol, disp) + if _ == reps - 1: + pip.flow_rate.aspirate = 150 + pip.flow_rate.dispense = 100 + pip.aspirate(vol, asp) + pip.dispense(vol, asp) + + pip.flow_rate.aspirate = 300 + pip.flow_rate.dispense = 300 + + def A_lysis(vol: float, source: Well) -> None: + """A Lysis.""" + ctx.comment("-----Mixing then transferring AL buffer-----") + num_transfers = math.ceil(vol / 980) + tiptrack(tips) + for i in range(num_cols): + if num_cols >= 5: + if i == 0: + height = 10 + else: + height = 1 + else: + height = 1 + src = source + tvol = vol / num_transfers + for t in range(num_transfers): + if i == 0 and t == 0: + for _ in range(3): + m1000.require_liquid_presence(src) + m1000.aspirate(tvol, src.bottom(1)) + m1000.dispense(tvol, src.bottom(4)) + m1000.require_liquid_presence(src) + m1000.aspirate(tvol, src.bottom(height)) + m1000.air_gap(10) + m1000.dispense(m1000.current_volume, samples_m[i].top()) + m1000.air_gap(20) + + for i in range(num_cols): + if i != 0: + tiptrack(tips) + mixing( + samples_m[i], m1000, tvol - 40, reps=10 if not dry_run else 1 + ) # vol is 250 AL + 180 sample + m1000.air_gap(20) + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() + + ctx.comment("-----Mixing then Heating AL and Sample-----") + + helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, A_lysis_time_1, False) + if not dry_run: + h_s.set_and_wait_for_temperature(55) + ctx.delay( + minutes=A_lysis_time_2, + msg="Incubating at 55C " + + str(heater_shaker_speed) + + " rpm for 10 minutes.", + ) + h_s.deactivate_shaker() + + def bind(vol: float) -> None: + """Bind. + + `bind` will perform magnetic bead binding on each sample in the + deepwell plate. Each channel of binding beads will be mixed before + transfer, and the samples will be mixed with the binding beads after + the transfer. The magnetic deck activates after the addition to all + samples, and the supernatant is removed after bead bining. + :param vol (float): The amount of volume to aspirate from the elution + buffer source and dispense to each well containing + beads. + :param park (boolean): Whether to save sample-corresponding tips + between adding elution buffer and transferring + supernatant to the final clean elutions PCR + plate. + """ + ctx.comment("-----Beginning Bind Steps-----") + tiptrack(tips) + for i, well in enumerate(samples_m): + num_trans = math.ceil(vol / 980) + vol_per_trans = vol / num_trans + source = binding_buffer[i // 3] + if i == 0: + reps = 6 if not dry_run else 1 + else: + reps = 1 + ctx.comment("-----Mixing Beads in Reservoir-----") + bead_mixing(source, m1000, vol_per_trans, reps=reps if not dry_run else 1) + # Transfer beads and binding from source to H-S plate + for t in range(num_trans): + if m1000.current_volume > 0: + # void air gap if necessary + m1000.dispense(m1000.current_volume, source.top()) + m1000.transfer( + vol_per_trans, source, well.top(), air_gap=20, new_tip="never" + ) + if t < num_trans - 1: + m1000.air_gap(20) + + ctx.comment("-----Mixing Beads in Plate-----") + for i in range(num_cols): + if i != 0: + tiptrack(tips) + mixing( + samples_m[i], m1000, vol + starting_vol, reps=10 if not dry_run else 1 + ) + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() + + ctx.comment("-----Incubating Beads and Bind on H-S-----") + + speed_val = heater_shaker_speed * 0.9 + helpers.set_hs_speed(ctx, h_s, speed_val, bind_time, True) + + # Transfer from H-S plate to Magdeck plate + helpers.move_labware_from_hs_to_mag_block( + ctx, sample_plate, h_s, magnetic_block + ) + for bindi in np.arange( + settling_time + 1, 0, -0.5 + ): # Settling time delay with countdown timer + ctx.delay( + minutes=0.5, + msg="There are " + str(bindi) + " minutes left in the incubation.", + ) + + # remove initial supernatant + remove_supernatant(vol + starting_vol) + + def wash(vol: float, source: List[Well]) -> None: + """Wash function.""" + global whichwash # Defines which wash the protocol is on to log on the app + + if source == wash1: + whichwash = 1 + if source == wash2: + whichwash = 2 + if source == wash3: + whichwash = 3 + + ctx.comment("-----Beginning Wash #" + str(whichwash) + "-----") + + num_trans = math.ceil(vol / 980) + vol_per_trans = vol / num_trans + tiptrack(tips) + for i, m in enumerate(samples_m): + src = source[i // 2] + for n in range(num_trans): + if m1000.current_volume > 0: + m1000.dispense(m1000.current_volume, src.top()) + m1000.transfer(vol_per_trans, src, m.top(), air_gap=20, new_tip="never") + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() + + helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, elute_wash_time, True) + + helpers.move_labware_from_hs_to_mag_block( + ctx, sample_plate, h_s, magnetic_block + ) + + for washi in np.arange( + settling_time, 0, -0.5 + ): # settling time timer for washes + ctx.delay( + minutes=0.5, + msg="There are " + + str(washi) + + " minutes left in wash " + + str(whichwash) + + " incubation.", + ) + + remove_supernatant(vol) + + def elute(vol: float) -> None: + """Elution Function.""" + ctx.comment("-----Beginning Elution Steps-----") + tiptrack(tips) + for i, (m, e) in enumerate(zip(samples_m, elution_samples_m)): + m1000.flow_rate.aspirate = 25 + m1000.aspirate(vol, e.bottom(dot_bottom)) + m1000.air_gap(20) + m1000.dispense(m1000.current_volume, m.top()) + m1000.flow_rate.aspirate = 150 + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() + + h_s.set_and_wait_for_shake_speed(heater_shaker_speed * 1.1) + speed_val = heater_shaker_speed * 1.1 + helpers.set_hs_speed(ctx, h_s, speed_val, elute_wash_time, True) + + # Transfer back to magnet + helpers.move_labware_from_hs_to_mag_block( + ctx, sample_plate, h_s, magnetic_block + ) + + for elutei in np.arange(settling_time, 0, -0.5): + ctx.delay( + minutes=0.5, + msg="Incubating on MagDeck for " + str(elutei) + " more minutes.", + ) + + for i, (m, e) in enumerate(zip(samples_m, elution_samples_m)): + tiptrack(tips) + m1000.flow_rate.dispense = 100 + m1000.flow_rate.aspirate = 150 + m1000.transfer( + vol, m.bottom(dot_bottom), e.bottom(5), air_gap=20, new_tip="never" + ) + m1000.blow_out(e.top(-2)) + m1000.air_gap(20) + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() + + """ + Here is where you can call the methods defined above to fit your specific + protocol. The normal sequence is: + """ + A_lysis(AL_total_vol, AL) + bind(binding_buffer_vol) + wash(wash1_vol, wash1) + wash(wash2_vol, wash2) + wash(wash3_vol, wash3) + if not dry_run: + drybeads = 10.0 # Number of minutes you want to dry for + else: + drybeads = 0.5 + for beaddry in np.arange(drybeads, 0, -0.5): + ctx.delay( + minutes=0.5, + msg="There are " + str(beaddry) + " minutes left in the drying step.", + ) + elute(elution_vol) diff --git a/abr-testing/abr_testing/protocols/api 2.20/9_Magmax_RNA_Cells_Flex_csv.py b/abr-testing/abr_testing/protocols/api 2.20/9_Magmax_RNA_Cells_Flex_csv.py new file mode 100644 index 00000000000..f4c94305bea --- /dev/null +++ b/abr-testing/abr_testing/protocols/api 2.20/9_Magmax_RNA_Cells_Flex_csv.py @@ -0,0 +1,587 @@ +"""Thermo MagMax RNA Extraction: Cells Multi-Channel.""" +import math +from opentrons import types +from opentrons.protocol_api import ( + ProtocolContext, + ParameterContext, + Well, + InstrumentContext, +) +from typing import List +from opentrons.protocol_api.module_contexts import ( + HeaterShakerContext, + MagneticBlockContext, + TemperatureModuleContext, +) + +import numpy as np +from abr_testing.protocols import helpers + +metadata = { + "author": "Zach Galluzzo ", + "protocolName": "Thermo MagMax RNA Extraction: Cells Multi-Channel", +} + +requirements = { + "robotType": "OT-3", + "apiLevel": "2.20", +} +""" +Slot A1: Tips 200 +Slot A2: Tips 200 +Slot A3: Temperature module (gen2) with 96 well PCR block and Armadillo 96 well PCR Plate +** Plate gets 55 ul per well in each well of the entire plate +Slot B1: Tips 200 +Slot B2: Tips 200 +Slot B3: Nest 1 Well Reservoir +Slot C1: Magblock +Slot C2: +Slot C3: +Slot D1: H-S with Nest 96 Well Deepwell and DW Adapter +Slot D2: Nest 12 well 15 ml Reservoir +Slot D3: Trash + +Reservoir 1: +Well 1 - 8120 ul +Well 2 - 6400 ul +Well 3-7 - 8550 ul +""" + +whichwash = 1 +sample_max = 48 +tip = 0 +drop_count = 0 +waste_vol = 0 + + +# Start protocol +def add_parameters(parameters: ParameterContext) -> None: + """Parameters.""" + parameters.add_csv_file( + variable_name="parameters_csv", + display_name="Parameters CSV File", + description="CSV file containing parameters for this protocol", + ) + + +def run(ctx: ProtocolContext) -> None: + """Protocol.""" + dry_run = False + inc_lysis = True + mount = "left" + res_type = "nest_12_reservoir_15ml" + TIP_TRASH = False + num_samples = 48 + wash_vol = 150 + lysis_vol = 140 + stop_vol = 100 + elution_vol = dnase_vol = 50 + # default="\protocols\csv_parameters\9_parameters.csv", + csv_params = ctx.params.parameters_csv.parse_as_csv() # type: ignore[attr-defined] + heater_shaker_speed = int(csv_params[1][0]) + dot_bottom = csv_params[1][1] + + # Protocol Parameters + deepwell_type = "nest_96_wellplate_2ml_deep" + if not dry_run: + settling_time = 2.0 + lysis_time = 1.0 + drybeads = 2.0 # Number of minutes you want to dry for + bind_time = wash_time = 5.0 + dnase_time = 10.0 + stop_time = elute_time = 3.0 + else: + settling_time = 0.25 + lysis_time = 0.25 + drybeads = elute_time = 0.25 + bind_time = wash_time = dnase_time = stop_time = 0.25 + bead_vol = 20 + ctx.load_trash_bin("A3") + h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] + h_s_adapter = h_s.load_adapter("opentrons_96_deep_well_adapter") + sample_plate = h_s_adapter.load_labware(deepwell_type, "Sample Plate") + h_s.close_labware_latch() + temp: TemperatureModuleContext = ctx.load_module( + helpers.temp_str, "D3" + ) # type: ignore[assignment] + temp_block = temp.load_adapter("opentrons_96_well_aluminum_block") + elutionplate = temp_block.load_labware( + "armadilo_96_wellplate_200ul_pcr_full_skirt", "Elution Plate" + ) + temp.set_temperature(4) + magblock: MagneticBlockContext = ctx.load_module( + helpers.mag_str, "C1" + ) # type: ignore[assignment] + waste = ( + ctx.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") + .wells()[0] + .top() + ) + res1 = ctx.load_labware(res_type, "D2", "reagent reservoir 1") + num_cols = math.ceil(num_samples / 8) + + # Load tips and combine all similar boxes + tips200 = ctx.load_labware("opentrons_flex_96_tiprack_200ul", "A1", "Tips 1") + tips201 = ctx.load_labware("opentrons_flex_96_tiprack_200ul", "A2", "Tips 2") + tips202 = ctx.load_labware("opentrons_flex_96_tiprack_200ul", "B1", "Tips 3") + tips203 = ctx.load_labware("opentrons_flex_96_tiprack_200ul", "B2", "Tips 4") + tips = [ + *tips200.wells()[num_samples:96], + *tips201.wells(), + *tips202.wells(), + *tips203.wells(), + ] + tips_sn = tips200.wells()[:num_samples] + + # load P1000M pipette + m1000 = ctx.load_instrument("flex_8channel_1000", mount) + + # Load Liquid Locations in Reservoir + elution_solution = elutionplate.rows()[0][:num_cols] + dnase1 = elutionplate.rows()[0][num_cols : 2 * num_cols] + lysis_ = res1.wells()[0] + stopreaction = res1.wells()[1] + wash1 = res1.wells()[2] + wash2 = res1.wells()[3] + wash3 = res1.wells()[4] + wash4 = res1.wells()[5] + wash5 = res1.wells()[6] + + """ + Here is where you can define the locations of your reagents. + """ + samples_m = sample_plate.rows()[0][:num_cols] # 20ul beads each well + cells_m = sample_plate.rows()[0][num_cols : 2 * num_cols] + elution_samples_m = elutionplate.rows()[0][:num_cols] + # Do the same for color mapping + beads_ = sample_plate.wells()[: (8 * num_cols)] + cells_ = sample_plate.wells()[(8 * num_cols) : (16 * num_cols)] + elution_samps = elutionplate.wells()[: (8 * num_cols)] + dnase1_ = elutionplate.wells()[(8 * num_cols) : (16 * num_cols)] + + colors = helpers.liquid_colors + + locations = [lysis_, wash1, wash2, wash3, wash4, wash5, stopreaction] + vols = [lysis_vol, wash_vol, wash_vol, wash_vol, wash_vol, wash_vol, stop_vol] + liquids = ["Lysis", "Wash 1", "Wash 2", "Wash 3", "Wash 4", "Wash 5", "Stop"] + + dnase_liq = ctx.define_liquid( + name="DNAse", description="DNAse", display_color="#C0C0C0" + ) + eluate = ctx.define_liquid( + name="Elution Buffer", description="Elution Buffer", display_color="#00FF00" + ) + bead = ctx.define_liquid(name="Beads", description="Beads", display_color="#FFA500") + sample = ctx.define_liquid( + name="Sample", description="Cell Pellet", display_color="#FFC0CB" + ) + + # Add liquids to non-reservoir labware + for i in beads_: + i.load_liquid(liquid=bead, volume=bead_vol) + for i in cells_: + i.load_liquid(liquid=sample, volume=0) + for i in dnase1_: + i.load_liquid(liquid=dnase_liq, volume=dnase_vol) + for i in elution_samps: + i.load_liquid(liquid=eluate, volume=elution_vol) + + delete = len(colors) - len(liquids) + + if delete >= 1: + for color_del in range(delete): + colors.pop(-1) + + def liquids_(liq: str, location: Well, color: str, vol: float) -> None: + """Define Liquids.""" + sampnum = 8 * (math.ceil(num_samples / 8)) + # Volume Calculation + extra_samples = math.ceil(1500 / vol) + + v = vol * (sampnum + extra_samples) + loaded_liq = ctx.define_liquid(name=liq, description=liq, display_color=color) + location.load_liquid(liquid=loaded_liq, volume=v) + + for x, (ll, l, c, v) in enumerate(zip(liquids, locations, colors, vols)): + liquids_(ll, l, c, v) + + m1000.flow_rate.aspirate = 50 + m1000.flow_rate.dispense = 150 + m1000.flow_rate.blow_out = 300 + + def tiptrack(pip: InstrumentContext, tipbox: List[Well]) -> None: + """Tip Track.""" + global tip + global drop_count + pip.pick_up_tip(tipbox[int(tip)]) + tip = tip + 8 + drop_count = drop_count + 8 + if drop_count >= 250: + drop_count = 0 + if TIP_TRASH: + ctx.pause("Empty Trash bin.") + + def remove_supernatant(vol: float) -> None: + """Remove Supernatant.""" + ctx.comment("-----Removing Supernatant-----") + m1000.flow_rate.aspirate = 30 + num_trans = math.ceil(vol / 180) + vol_per_trans = vol / num_trans + + for i, m in enumerate(samples_m): + m1000.pick_up_tip(tips_sn[8 * i]) + loc = m.bottom(dot_bottom) + for _ in range(num_trans): + if m1000.current_volume > 0: + # void air gap if necessary + m1000.dispense(m1000.current_volume, m.top()) + m1000.move_to(m.center()) + m1000.transfer(vol_per_trans, loc, waste, new_tip="never", air_gap=20) + m1000.blow_out(waste) + m1000.air_gap(20) + m1000.drop_tip(tips_sn[8 * i]) if TIP_TRASH else m1000.return_tip() + m1000.flow_rate.aspirate = 300 + # Move Plate From Magnet to H-S + helpers.move_labware_to_hs(ctx, sample_plate, h_s, h_s_adapter) + + def bead_mixing( + well: Well, pip: InstrumentContext, mvol: float, reps: int = 8 + ) -> None: + """Bead Mixing. + + 'mixing' will mix liquid that contains beads. This will be done by + aspirating from the bottom of the well and dispensing from the top as to + mix the beads with the other liquids as much as possible. Aspiration and + dispensing will also be reversed for a short to to ensure maximal mixing. + param well: The current well that the mixing will occur in. + param pip: The pipet that is currently attached/ being used. + param mvol: The volume that is transferred before the mixing steps. + param reps: The number of mix repetitions that should occur. Note~ + During each mix rep, there are 2 cycles of aspirating from bottom, + dispensing at the top and 2 cycles of aspirating from middle, + dispensing at the bottom + """ + center = well.top().move(types.Point(x=0, y=0, z=5)) + aspbot = well.bottom().move(types.Point(x=0, y=0, z=1)) + asptop = well.bottom().move(types.Point(x=2, y=-2, z=1)) + disbot = well.bottom().move(types.Point(x=-2, y=1.5, z=2)) + distop = well.bottom().move(types.Point(x=0, y=0, z=6)) + + if mvol > 1000: + mvol = 1000 + + vol = mvol * 0.9 + + pip.flow_rate.aspirate = 500 + pip.flow_rate.dispense = 500 + + pip.move_to(center) + for _ in range(reps): + pip.aspirate(vol, aspbot) + pip.dispense(vol, distop) + pip.aspirate(vol, asptop) + pip.dispense(vol, disbot) + if _ == reps - 1: + pip.flow_rate.aspirate = 100 + pip.flow_rate.dispense = 75 + pip.aspirate(vol, aspbot) + pip.dispense(vol, aspbot) + + pip.flow_rate.aspirate = 300 + pip.flow_rate.dispense = 300 + + def mixing(well: Well, pip: InstrumentContext, mvol: float, reps: int = 8) -> None: + """Mixing. + + 'mixing' will mix liquid that contains beads. This will be done by + aspirating from the bottom of the well and dispensing from the top as to + mix the beads with the other liquids as much as possible. Aspiration and + dispensing will also be reversed for a short to to ensure maximal mixing. + param well: The current well that the mixing will occur in. + param pip: The pipet that is currently attached/ being used. + param mvol: The volume that is transferred before the mixing steps. + param reps: The number of mix repetitions that should occur. Note~ + During each mix rep, there are 2 cycles of aspirating from bottom, + dispensing at the top and 2 cycles of aspirating from middle, + dispensing at the bottom + """ + center = well.top(5) + asp = well.bottom(dot_bottom) + disp = well.top(-8) + + if mvol > 1000: + mvol = 1000 + + vol = mvol * 0.9 + + pip.flow_rate.aspirate = 500 + pip.flow_rate.dispense = 500 + + pip.move_to(center) + for _ in range(reps): + pip.aspirate(vol, asp) + pip.dispense(vol, disp) + pip.aspirate(vol, asp) + pip.dispense(vol, disp) + if _ == reps - 1: + pip.flow_rate.aspirate = 100 + pip.flow_rate.dispense = 75 + pip.aspirate(vol, asp) + pip.dispense(vol, asp) + + pip.flow_rate.aspirate = 300 + pip.flow_rate.dispense = 300 + + def lysis(vol: float, source: Well) -> None: + """Lysis Steps.""" + ctx.comment("-----Beginning lysis steps-----") + num_transfers = math.ceil(vol / 180) + tiptrack(m1000, tips) + for i in range(num_cols): + src = source + tvol = vol / num_transfers + for t in range(num_transfers): + m1000.require_liquid_presence(src) + m1000.aspirate(tvol, src.bottom(1)) + m1000.dispense(m1000.current_volume, cells_m[i].top(-3)) + + # mix after adding all reagent to wells with cells + for i in range(num_cols): + if i != 0: + tiptrack(m1000, tips) + for x in range(8 if not dry_run else 1): + m1000.aspirate(tvol * 0.75, cells_m[i].bottom(dot_bottom)) + m1000.dispense(tvol * 0.75, cells_m[i].bottom(8)) + if x == 3: + ctx.delay(minutes=0.0167) + m1000.blow_out(cells_m[i].bottom(1)) + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() + + helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, lysis_time, True) + + def bind() -> None: + """Bind. + + `bind` will perform magnetic bead binding on each sample in the + deepwell plate. Each channel of binding beads will be mixed before + transfer, and the samples will be mixed with the binding beads after + the transfer. The magnetic deck activates after the addition to all + samples, and the supernatant is removed after bead binding. + :param vol (float): The amount of volume to aspirate from the elution + buffer source and dispense to each well containing + beads. + :param park (boolean): Whether to save sample-corresponding tips + between adding elution buffer and transferring + supernatant to the final clean elutions PCR + plate. + """ + ctx.comment("-----Beginning bind steps-----") + for i, well in enumerate(samples_m): + # Transfer cells+lysis/bind to wells with beads + tiptrack(m1000, tips) + m1000.aspirate(185, cells_m[i].bottom(dot_bottom)) + m1000.air_gap(10) + m1000.dispense(m1000.current_volume, well.bottom(8)) + # Mix after transfer + bead_mixing(well, m1000, 130, reps=5 if not dry_run else 1) + m1000.air_gap(10) + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() + helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, bind_time, True) + + # Transfer from H-S plate to Magdeck plate + helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) + + for bindi in np.arange( + settling_time, 0, -0.5 + ): # Settling time delay with countdown timer + ctx.delay( + minutes=0.5, + msg="There are " + str(bindi) + " minutes left in the incubation.", + ) + + # remove initial supernatant + remove_supernatant(180) + + def wash(vol: float, source: Well) -> None: + """Wash Function.""" + global whichwash # Defines which wash the protocol is on to log on the app + + if source == wash1: + whichwash = 1 + if source == wash2: + whichwash = 2 + if source == wash3: + whichwash = 3 + if source == wash4: + whichwash = 4 + + ctx.comment("-----Now starting Wash #" + str(whichwash) + "-----") + + tiptrack(m1000, tips) + num_trans = math.ceil(vol / 180) + vol_per_trans = vol / num_trans + for i, m in enumerate(samples_m): + src = source + m1000.require_liquid_presence(src) + for n in range(num_trans): + m1000.aspirate(vol_per_trans, src) + m1000.air_gap(10) + m1000.dispense(m1000.current_volume, m.top(-2)) + ctx.delay(seconds=2) + m1000.blow_out(m.top(-2)) + m1000.air_gap(10) + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() + + # Shake for 5 minutes to mix wash with beads + helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, wash_time, True) + + # Transfer from H-S plate to Magdeck plate + helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) + + for washi in np.arange( + settling_time, 0, -0.5 + ): # settling time timer for washes + ctx.delay( + minutes=0.5, + msg="There are " + + str(washi) + + " minutes left in wash " + + str(whichwash) + + " incubation.", + ) + + remove_supernatant(vol) + + def dnase(vol: float, source: List[Well]) -> None: + """Steps for DNAseI.""" + ctx.comment("-----DNAseI Steps Beginning-----") + num_trans = math.ceil(vol / 180) + vol_per_trans = vol / num_trans + tiptrack(m1000, tips) + for i, m in enumerate(samples_m): + src = source[i] + m1000.flow_rate.aspirate = 10 + for n in range(num_trans): + if m1000.current_volume > 0: + m1000.dispense(m1000.current_volume, src.top()) + m1000.aspirate(vol_per_trans, src.bottom(dot_bottom)) + m1000.dispense(vol_per_trans, m.top(-3)) + m1000.blow_out(m.top(-3)) + m1000.air_gap(20) + + m1000.flow_rate.aspirate = 300 + + # Is this mixing needed? \/\/\/ + for i in range(num_cols): + if i != 0: + tiptrack(m1000, tips) + mixing(samples_m[i], m1000, 45, reps=5 if not dry_run else 1) + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() + + # Shake for 10 minutes to mix DNAseI + helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, dnase_time, True) + + def stop_reaction(vol: float, source: Well) -> None: + """Adding stop solution.""" + ctx.comment("-----Adding Stop Solution-----") + tiptrack(m1000, tips) + num_trans = math.ceil(vol / 180) + vol_per_trans = vol / num_trans + for i, m in enumerate(samples_m): + src = source + for n in range(num_trans): + if m1000.current_volume > 0: + m1000.dispense(m1000.current_volume, src.top()) + m1000.transfer(vol_per_trans, src, m.top(), air_gap=20, new_tip="never") + m1000.blow_out(m.top(-3)) + m1000.air_gap(20) + + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() + + # Shake for 3 minutes to mix wash with beads + helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, stop_time, True) + + # Transfer from H-S plate to Magdeck plate + helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) + + for stop in np.arange(settling_time, 0, -0.5): + ctx.delay( + minutes=0.5, + msg="There are " + str(stop) + " minutes left in this incubation.", + ) + + remove_supernatant(vol + 50) + + def elute(vol: float) -> None: + """Elution.""" + ctx.comment("-----Elution Beginning-----") + tiptrack(m1000, tips) + m1000.flow_rate.aspirate = 10 + for i, m in enumerate(samples_m): + loc = m.top(-2) + m1000.aspirate(vol, elution_solution[i]) + m1000.air_gap(10) + m1000.dispense(m1000.current_volume, loc) + m1000.blow_out(m.top(-3)) + m1000.air_gap(10) + + m1000.flow_rate.aspirate = 300 + + # Is this mixing needed? \/\/\/ + for i in range(num_cols): + if i != 0: + tiptrack(m1000, tips) + for mixes in range(10): + m1000.aspirate(elution_vol - 10, samples_m[i]) + m1000.dispense(elution_vol - 10, samples_m[i].bottom(10)) + if mixes == 9: + m1000.flow_rate.dispense = 20 + m1000.aspirate(elution_vol - 10, samples_m[i]) + m1000.dispense(elution_vol - 10, samples_m[i].bottom(10)) + m1000.flow_rate.dispense = 300 + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() + + # Shake for 3 minutes to mix wash with beads + helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, elute_time, True) + + # Transfer from H-S plate to Magdeck plate + helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) + + for elutei in np.arange(settling_time, 0, -0.5): + ctx.delay( + minutes=0.5, + msg="Incubating on MagDeck for " + str(elutei) + " more minutes.", + ) + + ctx.comment("-----Trasnferring Sample to Elution Plate-----") + for i, (m, e) in enumerate(zip(samples_m, elution_samples_m)): + tiptrack(m1000, tips) + loc = m.bottom(dot_bottom) + m1000.transfer(vol, loc, e.bottom(5), air_gap=20, new_tip="never") + m1000.blow_out(e.top(-2)) + m1000.air_gap(20) + m1000.drop_tip() if TIP_TRASH else m1000.return_tip() + + """ + Here is where you can call the methods defined above to fit your specific + protocol. The normal sequence is: + """ + if inc_lysis: + lysis(lysis_vol, lysis_) + bind() + wash(wash_vol, wash1) + wash(wash_vol, wash2) + # dnase1 treatment + dnase(dnase_vol, dnase1) + stop_reaction(stop_vol, stopreaction) + # Resume washes + wash(wash_vol, wash3) + wash(wash_vol, wash4) + wash(wash_vol, wash5) + + for beaddry in np.arange(drybeads, 0, -0.5): + ctx.delay( + minutes=0.5, + msg="There are " + str(beaddry) + " minutes left in the drying step.", + ) + elute(elution_vol) diff --git a/abr-testing/abr_testing/protocols/csv_parameters/9_parameters.csv b/abr-testing/abr_testing/protocols/csv_parameters/9_parameters.csv new file mode 100644 index 00000000000..a5f947d97d5 --- /dev/null +++ b/abr-testing/abr_testing/protocols/csv_parameters/9_parameters.csv @@ -0,0 +1,2 @@ +heater_shaker_speed, dot_bottom +2000, 0.1 \ No newline at end of file diff --git a/abr-testing/abr_testing/protocols/helpers.py b/abr-testing/abr_testing/protocols/helpers.py index d7392a8c67e..5032cda33ac 100644 --- a/abr-testing/abr_testing/protocols/helpers.py +++ b/abr-testing/abr_testing/protocols/helpers.py @@ -1,7 +1,19 @@ """Helper functions commonly used in protocols.""" -from opentrons.protocol_api import ProtocolContext, Labware, InstrumentContext +from opentrons.protocol_api import ( + ProtocolContext, + Labware, + InstrumentContext, + ParameterContext, +) from typing import Tuple +from opentrons.protocol_api.module_contexts import ( + HeaterShakerContext, + MagneticBlockContext, + ThermocyclerContext, +) + +from typing import List def load_common_liquid_setup_labware_and_instruments( @@ -17,3 +29,182 @@ def load_common_liquid_setup_labware_and_instruments( # Source_reservoir source_reservoir = protocol.load_labware("axygen_1_reservoir_90ml", "C2") return source_reservoir, p1000 + + +def create_pipette_mount_parameter(parameters: ParameterContext) -> None: + """Create parameter to specify pipette mount.""" + parameters.add_str( + variable_name="pipette_mount", + display_name="Pipette Mount", + choices=[ + {"display_name": "Left", "value": "left"}, + {"display_name": "Right", "value": "right"}, + ], + default="left", + ) + + +def create_disposable_lid_parameter(parameters: ParameterContext) -> None: + """Create parameter to use/not use disposable lid.""" + parameters.add_bool( + variable_name="disposable_lid", + display_name="Disposable Lid", + description="True means use lid.", + default=True, + ) + + +def create_tip_size_parameter(parameters: ParameterContext) -> None: + """Create parameter for tip size.""" + parameters.add_str( + variable_name="tip_size", + display_name="Tip Size", + description="Set Tip Size", + choices=[ + {"display_name": "50 uL", "value": "opentrons_flex_96_tiprack_50ul"}, + {"display_name": "200 µL", "value": "opentrons_flex_96_tiprack_200ul"}, + {"display_name": "1000 µL", "value": "opentrons_flex_96_tiprack_1000ul"}, + ], + default="opentrons_flex_96_tiprack_1000ul", + ) + + +def create_dot_bottom_parameter(parameters: ParameterContext) -> None: + """Create parameter for dot bottom value.""" + parameters.add_float( + variable_name="dot_bottom", + display_name=".bottom", + description="Lowest value pipette will go to.", + default=0.5, + choices=[ + {"display_name": "0.0", "value": 0.0}, + {"display_name": "0.1", "value": 0.1}, + {"display_name": "0.2", "value": 0.2}, + {"display_name": "0.3", "value": 0.3}, + {"display_name": "0.4", "value": 0.4}, + {"display_name": "0.5", "value": 0.5}, + {"display_name": "0.6", "value": 0.6}, + {"display_name": "0.7", "value": 0.7}, + {"display_name": "0.8", "value": 0.8}, + {"display_name": "0.9", "value": 0.9}, + {"display_name": "1.0", "value": 1.0}, + ], + ) + + +def create_hs_speed_parameter(parameters: ParameterContext) -> None: + """Create parameter for max heatershaker speed.""" + parameters.add_int( + variable_name="heater_shaker_speed", + display_name="Heater Shaker Shake Speed", + description="Speed to set the heater shaker to", + default=2000, + minimum=200, + maximum=3000, + unit="rpm", + ) + + +def move_labware_from_hs_to_mag_block( + protocol: ProtocolContext, + labware_to_move: Labware, + hs: HeaterShakerContext, + mag_block: MagneticBlockContext, +) -> None: + """Move labware from heatershaker to magnetic block.""" + hs.open_labware_latch() + protocol.move_labware(labware_to_move, mag_block, use_gripper=True) + hs.close_labware_latch() + + +def move_labware_to_hs( + protocol: ProtocolContext, + labware_to_move: Labware, + hs: HeaterShakerContext, + hs_adapter: Labware, +) -> None: + """Move labware to heatershaker.""" + hs.open_labware_latch() + protocol.move_labware(labware_to_move, hs_adapter, use_gripper=True) + hs.close_labware_latch() + + +def set_hs_speed( + protocol: ProtocolContext, + hs: HeaterShakerContext, + hs_speed: int, + time_min: float, + deactivate: bool, +) -> None: + """Set heatershaker for a speed and duration.""" + hs.set_and_wait_for_shake_speed(hs_speed) + protocol.delay( + minutes=time_min, + msg=f"Shake at {hs_speed} rpm for {time_min} minutes.", + ) + if deactivate: + hs.deactivate_shaker() + + +def load_disposable_lids( + protocol: ProtocolContext, num_of_lids: int, deck_slot: str +) -> List[Labware]: + """Load Stack of Disposable lids.""" + unused_lids = [ + protocol.load_labware("opentrons_tough_pcr_auto_sealing_lid", deck_slot) + ] + for i in range(num_of_lids - 1): + unused_lids.append( + unused_lids[-1].load_labware("opentrons_tough_pcr_auto_sealing_lid") + ) + unused_lids.reverse() + return unused_lids + + +def use_disposable_lid_with_tc( + protocol: ProtocolContext, + unused_lids: List[Labware], + used_lids: List[Labware], + plate_in_thermocycler: Labware, + thermocycler: ThermocyclerContext, +) -> Tuple[Labware, List[Labware], List[Labware]]: + """Use disposable lid with thermocycler.""" + lid_on_plate = unused_lids[0] + protocol.move_labware(lid_on_plate, plate_in_thermocycler, use_gripper=True) + # Remove lid from the list + unused_lids.pop(0) + used_lids.append(lid_on_plate) + thermocycler.close_lid() + return lid_on_plate, unused_lids, used_lids + + +# CONSTANTS + +liquid_colors = [ + "#008000", + "#008000", + "#A52A2A", + "#A52A2A", + "#00FFFF", + "#0000FF", + "#800080", + "#ADD8E6", + "#FF0000", + "#FFFF00", + "#FF00FF", + "#00008B", + "#7FFFD4", + "#FFC0CB", + "#FFA500", + "#00FF00", + "#C0C0C0", +] + +hs_adapter_str = "opentrons_96_pcr_adapter" +hs_str = "heaterShakerModuleV1" +mag_str = "magneticBlockV1" +temp_adapter_str = "opentrons_96_well_aluminum_block" +temp_str = "temperature module gen2" +tc_str = "thermocycler module gen2" + +# TODO: Create dictionary of labware, module, and adapter. From 4b1341b3eef88658950456b2e497b74de61ec05c Mon Sep 17 00:00:00 2001 From: rclarke0 Date: Mon, 28 Oct 2024 12:56:28 -0400 Subject: [PATCH 04/13] calibration run command --- .../abr_testing/data_collection/abr_calibration_logs.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/abr-testing/abr_testing/data_collection/abr_calibration_logs.py b/abr-testing/abr_testing/data_collection/abr_calibration_logs.py index 1440dfd70a8..d632a53dd31 100644 --- a/abr-testing/abr_testing/data_collection/abr_calibration_logs.py +++ b/abr-testing/abr_testing/data_collection/abr_calibration_logs.py @@ -363,3 +363,6 @@ def run( folder_name = args.folder_name[0] google_sheet_name = args.google_sheet_name[0] email = args.email[0] + run( + storage_directory, folder_name, google_sheet_name, email + ) From 04c266f4def0920d9592da154610a713af797dfc Mon Sep 17 00:00:00 2001 From: rclarke0 Date: Tue, 29 Oct 2024 16:18:31 -0400 Subject: [PATCH 05/13] protocol drafts --- abr-testing/abr_testing/protocols/__init__.py | 1 + .../api 2.20/bms_pcr_protocol_220api.py | 207 ++++++++++++++++++ .../protocols/csv_parameters/2_samplevols.csv | 25 +++ abr-testing/abr_testing/protocols/helpers.py | 20 +- .../test_protocols/tc_lid_x_offset_test.py | 97 ++++++++ 5 files changed, 343 insertions(+), 7 deletions(-) create mode 100644 abr-testing/abr_testing/protocols/__init__.py create mode 100644 abr-testing/abr_testing/protocols/api 2.20/bms_pcr_protocol_220api.py create mode 100644 abr-testing/abr_testing/protocols/csv_parameters/2_samplevols.csv create mode 100644 abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py diff --git a/abr-testing/abr_testing/protocols/__init__.py b/abr-testing/abr_testing/protocols/__init__.py new file mode 100644 index 00000000000..309f19697cf --- /dev/null +++ b/abr-testing/abr_testing/protocols/__init__.py @@ -0,0 +1 @@ +"""protocols.""" \ No newline at end of file diff --git a/abr-testing/abr_testing/protocols/api 2.20/bms_pcr_protocol_220api.py b/abr-testing/abr_testing/protocols/api 2.20/bms_pcr_protocol_220api.py new file mode 100644 index 00000000000..54c121f9294 --- /dev/null +++ b/abr-testing/abr_testing/protocols/api 2.20/bms_pcr_protocol_220api.py @@ -0,0 +1,207 @@ +"""BMS PCR Protocol.""" + +from opentrons.protocol_api import ParameterContext, ProtocolContext, Labware +from opentrons.protocol_api.module_contexts import ThermocyclerContext, TemperatureModuleContext +from opentrons.protocol_api import SINGLE +from abr_testing.protocols import helpers +import threading +from opentrons.hardware_control.modules.types import ThermocyclerStep +from typing import List + + +metadata = { + 'protocolName': 'PCR Protocol with TC Auto Sealing Lid', + 'author': 'Rami Farawi None: + """Protocol.""" + pipette_mount = ctx.params.pipette_mount + disposable_lid = ctx.params.disposable_lid + csv_samp = ctx.params.samples_csv + + real_mode = True + # DECK SETUP AND LABWARE + + tc_mod: ThermocyclerContext = ctx.load_module('thermocyclerModuleV2') + + tc_mod.open_lid() + tc_mod.set_lid_temperature(105) + temp_mod: TemperatureModuleContext = ctx.load_module('temperature module gen2', location='D3') + reagent_rack = temp_mod.load_labware( + 'opentrons_24_aluminumblock_nest_1.5ml_snapcap') # check if 2mL + + dest_plate = tc_mod.load_labware('opentrons_96_wellplate_200ul_pcr_full_skirt') # do I change this to tough plate if they run pcr? + + source_plate = ctx.load_labware('opentrons_96_wellplate_200ul_pcr_full_skirt', location="D1") # do I change this to their plate? + + tiprack_50 = [ctx.load_labware('opentrons_flex_96_tiprack_50ul', slot) for slot in [8, 9]] + + # Opentrons tough pcr auto sealing lids + if disposable_lid: + unused_lids = [ctx.load_labware("opentrons_tough_pcr_auto_sealing_lid", "C3")] + for i in range(2): + unused_lids.append(unused_lids[-1].load_labware("opentrons_tough_pcr_auto_sealing_lid")) + unused_lids.reverse() + used_lids = [] + + # LOAD PIPETTES + p50 = ctx.load_instrument( + "flex_8channel_50", pipette_mount, tip_racks=tiprack_50, liquid_presence_detection = True) + p50.configure_nozzle_layout( + style=SINGLE, + start="A1", + tip_racks=tiprack_50) + ctx.load_trash_bin("A3") + ctx.define_liquid(name="Mastermix", description='Mastermix', display_color='#008000') + ctx.define_liquid(name="Water", description='Water', display_color='#A52A2A') + ctx.define_liquid(name="DNA", description='DNA', display_color='#A52A2A') + + # mapping + csv_lines = [[val.strip() for val in line.split(',')] + for line in csv_samp.splitlines() + if line.split(',')[0].strip()][1:] + + + temp_mod.set_temperature(4) + + + water = reagent_rack['B1'] + water.load_liquid(liquid=water_liq, volume=1500) + # + mmx_pic = reagent_rack.rows()[0] + for mmx_well in mmx_pic: + mmx_well.load_liquid(liquid=mmx_liq, volume=1500) + + dna_pic = source_plate.wells() + for dna_well in dna_pic: + dna_well.load_liquid(liquid=dna_liq, volume=50) + + # adding water + ctx.comment('\n\n----------ADDING WATER----------\n') + p50.pick_up_tip() + # p50.aspirate(40, water) # prewet + # p50.dispense(40, water) + for row in csv_lines: + water_vol = row[1] + if water_vol.lower() == 'x': + continue + water_vol = int(row[1]) + dest_well = row[0] + if water_vol == 0: + break + + p50.configure_for_volume(water_vol) + p50.aspirate(water_vol, water) + p50.dispense(water_vol, dest_plate[dest_well], rate=0.5) + p50.configure_for_volume(50) + + # p50.blow_out() + p50.drop_tip() + + # adding Mastermix + ctx.comment('\n\n----------ADDING MASTERMIX----------\n') + for i, row in enumerate(csv_lines): + p50.pick_up_tip() + mmx_vol = row[3] + if mmx_vol.lower() == 'x': + continue + + if i == 0: + mmx_tube = row[4] + mmx_tube_check = mmx_tube + mmx_tube = row[4] + if mmx_tube_check != mmx_tube: + + p50.drop_tip() + p50.pick_up_tip() + + if not p50.has_tip: + p50.pick_up_tip() + + mmx_vol = int(row[3]) + dest_well = row[0] + + if mmx_vol == 0: + break + p50.configure_for_volume(mmx_vol) + p50.aspirate(mmx_vol, reagent_rack[mmx_tube]) + p50.dispense(mmx_vol, dest_plate[dest_well].top()) + ctx.delay(seconds=2) + p50.blow_out() + p50.touch_tip() + p50.configure_for_volume(50) + p50.drop_tip() + + if p50.has_tip: + p50.drop_tip() + + # adding DNA + ctx.comment('\n\n----------ADDING DNA----------\n') + for row in csv_lines: + + dna_vol = row[2] + if dna_vol.lower() == 'x': + continue + + p50.pick_up_tip() + + dna_vol = int(row[2]) + dest_and_source_well = row[0] + + + if dna_vol == 0: + break + p50.configure_for_volume(dna_vol) + p50.aspirate(dna_vol, source_plate[dest_and_source_well]) + p50.dispense(dna_vol, dest_plate[dest_and_source_well], rate=0.5) + + p50.mix(10, 0.7*rxn_vol if 0.7*rxn_vol < 30 else 30, dest_plate[dest_and_source_well]) + p50.drop_tip() + p50.configure_for_volume(50) + + ctx.comment('\n\n-----------Running PCR------------\n') + + if real_mode: + + profile1: List[ThermocyclerStep] = [ + {'temperature': 95, 'hold_time_minutes': 2}, + ] + profile2: List[ThermocyclerStep] = [ + + {'temperature': 98, 'hold_time_seconds': 10}, + {'temperature': 58, 'hold_time_seconds': 10}, + {'temperature': 72, 'hold_time_seconds': 30} + ] + profile3: List[ThermocyclerStep] = [ + {'temperature': 72, 'hold_time_minutes': 5} + ] + if disposable_lid: + lid_on_plate, unused_lids, used_lids = helpers.use_disposable_lid_with_tc(ctx, unused_lids, used_lids, dest_plate, tc_mod) + else: + tc_mod.close_lid() + tc_mod.execute_profile(steps=profile1, repetitions=1, block_max_volume=50) + tc_mod.execute_profile(steps=profile2, repetitions=30, block_max_volume=50) + tc_mod.execute_profile(steps=profile3, repetitions=1, block_max_volume=50) + tc_mod.set_block_temperature(4) + + tc_mod.open_lid() + if disposable_lid: + if len(used_lids) <= 1: + ctx.move_labware(lid_on_plate, "C2", use_gripper = True) + else: + ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper = True) diff --git a/abr-testing/abr_testing/protocols/csv_parameters/2_samplevols.csv b/abr-testing/abr_testing/protocols/csv_parameters/2_samplevols.csv new file mode 100644 index 00000000000..fa50562e68b --- /dev/null +++ b/abr-testing/abr_testing/protocols/csv_parameters/2_samplevols.csv @@ -0,0 +1,25 @@ +Destination Well,Water Transfer Volume (ul),DNA Transfer Volume (ul),Mastermix Volume (ul),Mastermix Source Tube +A1,3,7,40,A1 +B1,0,10,40,A1 +C1,10,0,40,A1 +D1,3,7,40,A1 +E1,2,8,40,A2 +F1,1,9,40,A2 +G1,5,5,40,A2 +H1,3,7,40,A3 +A2,3,7,40,A3 +B2,3,7,40,A3 +C2,3,7,40,A3 +D2,3,7,40,A3 +E2,3,7,40,A3 +F2,3,7,40,A3 +G2,3,7,40,A3 +H2,3,7,40,A3 +A3,3,7,40,A3 +B3,3,7,40,A3 +C3,3,7,45,A3 +D3,3,7,45,A3 +E3,3,5,45,A3 +F3,3,5,45,A3 +G3,3,5,45,A6 +H3,3,4,45,A5 \ No newline at end of file diff --git a/abr-testing/abr_testing/protocols/helpers.py b/abr-testing/abr_testing/protocols/helpers.py index 5032cda33ac..64e44df4685 100644 --- a/abr-testing/abr_testing/protocols/helpers.py +++ b/abr-testing/abr_testing/protocols/helpers.py @@ -13,7 +13,7 @@ ThermocyclerContext, ) -from typing import List +from typing import List, Union def load_common_liquid_setup_labware_and_instruments( @@ -147,16 +147,22 @@ def set_hs_speed( def load_disposable_lids( - protocol: ProtocolContext, num_of_lids: int, deck_slot: str + protocol: ProtocolContext, num_of_lids: int, deck_slot: List[str] ) -> List[Labware]: """Load Stack of Disposable lids.""" unused_lids = [ - protocol.load_labware("opentrons_tough_pcr_auto_sealing_lid", deck_slot) + protocol.load_labware("opentrons_tough_pcr_auto_sealing_lid", deck_slot[0]) ] - for i in range(num_of_lids - 1): - unused_lids.append( - unused_lids[-1].load_labware("opentrons_tough_pcr_auto_sealing_lid") - ) + if len(deck_slot) == 1: + for i in range(num_of_lids - 1): + unused_lids.append( + unused_lids[-1].load_labware("opentrons_tough_pcr_auto_sealing_lid") + ) + else: + for i in range(len(deck_slot)-1): + unused_lids.append( + protocol.load_labware("opentrons_tough_pcr_auto_sealing_lid", deck_slot[i]) + ) unused_lids.reverse() return unused_lids diff --git a/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py b/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py new file mode 100644 index 00000000000..e1707a4113b --- /dev/null +++ b/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py @@ -0,0 +1,97 @@ +"""Protocol to Test the Stacking and Movement of Tough Auto Seal Lid.""" +from typing import List, Union +from opentrons.protocol_api import ( + ParameterContext, + ProtocolContext, + Labware, +) +from opentrons.protocol_api.module_contexts import ( + ThermocyclerContext, +) +from abr_testing.protocols import helpers + + +metadata = {"protocolName": "Flat and Stacked Offset TC Lid Testing"} +requirements = {"robotType": "Flex", "apiLevel": "2.20"} + + +def add_parameters(parameters: ParameterContext) -> None: + """Add parameters.""" + parameters.add_int( + variable_name="lids_in_a_stack", + display_name="Num of Lids in Stack", + minimum = 1, + maximum = 5, + default = 1 + ) + parameters.add_float( + variable_name = "x_offset", + display_name= "X Offset", + choices=[ + {"display_name": "-1.4", "value": -1.4}, + {"display_name": "-1.3", "value": -1.3}, + {"display_name": "-1.2", "value": -1.2}, + {"display_name": "-1.1", "value": -1.1}, + {"display_name": "-1", "value": -1}, + {"display_name": "-0.9", "value": -0.9}, + {"display_name": "-0.8", "value": -0.8}, + {"display_name": "-0.7", "value": -0.7}, + {"display_name": "-0.6", "value": -0.6}, + {"display_name": "-0.5", "value": -0.5}, + {"display_name": "-0.4", "value": -0.4}, + {"display_name": "-0.3", "value": -0.3}, + {"display_name": "-0.2", "value": -0.2}, + {"display_name": "-0.1", "value": -0.1}, + {"display_name": "0.0", "value": 0.0}, + {"display_name": "-0.1", "value": 0.1}, + {"display_name": "-0.1", "value": 0.2}, + {"display_name": "-0.1", "value": 0.3}, + {"display_name": "-0.1", "value": 0.4}, + {"display_name": "-0.1", "value": 0.5}, + {"display_name": "1.5", "value": 1.5}, + {"display_name": "1.6", "value": 1.6}, + {"display_name": "1.7", "value": 1.7}, + {"display_name": "1.8", "value": 1.8}, + ], + default = 0.0 + ) + +def run(protocol: ProtocolContext) -> None: + """Runs protocol that moves lids and stacks them.""" + # Load Parameters + lids_in_stack = protocol.params.lids_in_a_stack # type: ignore[attr-defined] + x_offset = protocol.params.x_offset # type: ignore[attr-defined] + # Thermocycler + thermocycler: ThermocyclerContext = protocol.load_module( + "thermocyclerModuleV2" + ) # type: ignore[assignment] + plate_in_cycler = thermocycler.load_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt" + ) + thermocycler.open_lid() + # Load Lids + if lids_in_stack == 1: + slot_locations = ["D2", "C2", "B2", "C3", "B3"] + else: + slot_locations = ["D2"] + lids = helpers.load_disposable_lids(protocol, lids_in_stack, slot_locations) + drop_offset = {"x": x_offset, "y": 0, "z": 0} + slot = 0 + for lid in lids: + protocol.comment( + f"Offset {x_offset}, Lid # {slot+1}" + ) + # move lid to plate in thermocycler + protocol.move_labware( + lid, plate_in_cycler, use_gripper=True, drop_offset=drop_offset + ) + + if slot == 0: + move_location = "C1" + else: + move_location = prev_moved_lid + + protocol.move_labware(lid, move_location, use_gripper=True) + slot +=1 + prev_moved_lid = lid + From f5f28b6df2674847a02bd43ab613ef974c34b59f Mon Sep 17 00:00:00 2001 From: rclarke0 Date: Wed, 30 Oct 2024 15:54:55 -0400 Subject: [PATCH 06/13] lint and formatting issues --- .../data_collection/abr_calibration_logs.py | 4 +- abr-testing/abr_testing/protocols/__init__.py | 2 +- .../12_KAPA HyperPlus Library Prep.py | 2 +- ...omplex protocol with single tip Pick Up.py | 2 +- .../api 2.20/bms_pcr_protocol_220api.py | 154 ++++++++++-------- abr-testing/abr_testing/protocols/helpers.py | 8 +- .../test_protocols/tc_lid_x_offset_test.py | 99 +++++------ 7 files changed, 143 insertions(+), 128 deletions(-) diff --git a/abr-testing/abr_testing/data_collection/abr_calibration_logs.py b/abr-testing/abr_testing/data_collection/abr_calibration_logs.py index d632a53dd31..f1501609605 100644 --- a/abr-testing/abr_testing/data_collection/abr_calibration_logs.py +++ b/abr-testing/abr_testing/data_collection/abr_calibration_logs.py @@ -363,6 +363,4 @@ def run( folder_name = args.folder_name[0] google_sheet_name = args.google_sheet_name[0] email = args.email[0] - run( - storage_directory, folder_name, google_sheet_name, email - ) + run(storage_directory, folder_name, google_sheet_name, email) diff --git a/abr-testing/abr_testing/protocols/__init__.py b/abr-testing/abr_testing/protocols/__init__.py index 309f19697cf..2f0d01ea241 100644 --- a/abr-testing/abr_testing/protocols/__init__.py +++ b/abr-testing/abr_testing/protocols/__init__.py @@ -1 +1 @@ -"""protocols.""" \ No newline at end of file +"""protocols.""" diff --git a/abr-testing/abr_testing/protocols/api 2.20/12_KAPA HyperPlus Library Prep.py b/abr-testing/abr_testing/protocols/api 2.20/12_KAPA HyperPlus Library Prep.py index d60cfe405fd..4f9fe05d976 100644 --- a/abr-testing/abr_testing/protocols/api 2.20/12_KAPA HyperPlus Library Prep.py +++ b/abr-testing/abr_testing/protocols/api 2.20/12_KAPA HyperPlus Library Prep.py @@ -153,7 +153,7 @@ def run(ctx: ProtocolContext) -> None: trash = ctx.load_waste_chute() # Load TC Lids - unused_lids = helpers.load_disposable_lids(ctx, 5, "C3") + unused_lids = helpers.load_disposable_lids(ctx, 5, ["C3"]) # Import Global Variables global tip50 diff --git a/abr-testing/abr_testing/protocols/api 2.20/5_96ch complex protocol with single tip Pick Up.py b/abr-testing/abr_testing/protocols/api 2.20/5_96ch complex protocol with single tip Pick Up.py index 53b68503202..502e89cf8a9 100644 --- a/abr-testing/abr_testing/protocols/api 2.20/5_96ch complex protocol with single tip Pick Up.py +++ b/abr-testing/abr_testing/protocols/api 2.20/5_96ch complex protocol with single tip Pick Up.py @@ -62,7 +62,7 @@ def run(ctx: ProtocolContext) -> None: helpers.temp_str, "C1" ) # type: ignore[assignment] if disposable_lid: - unused_lids = helpers.load_disposable_lids(ctx, 3, "A4") + unused_lids = helpers.load_disposable_lids(ctx, 3, ["A4"]) used_lids: List[Labware] = [] thermocycler.open_lid() h_s.open_labware_latch() diff --git a/abr-testing/abr_testing/protocols/api 2.20/bms_pcr_protocol_220api.py b/abr-testing/abr_testing/protocols/api 2.20/bms_pcr_protocol_220api.py index 54c121f9294..873f7026d09 100644 --- a/abr-testing/abr_testing/protocols/api 2.20/bms_pcr_protocol_220api.py +++ b/abr-testing/abr_testing/protocols/api 2.20/bms_pcr_protocol_220api.py @@ -1,104 +1,114 @@ """BMS PCR Protocol.""" from opentrons.protocol_api import ParameterContext, ProtocolContext, Labware -from opentrons.protocol_api.module_contexts import ThermocyclerContext, TemperatureModuleContext +from opentrons.protocol_api.module_contexts import ( + ThermocyclerContext, + TemperatureModuleContext, +) from opentrons.protocol_api import SINGLE from abr_testing.protocols import helpers -import threading from opentrons.hardware_control.modules.types import ThermocyclerStep from typing import List metadata = { - 'protocolName': 'PCR Protocol with TC Auto Sealing Lid', - 'author': 'Rami Farawi None: + """Parameters.""" helpers.create_pipette_mount_parameter(parameters) helpers.create_disposable_lid_parameter(parameters) parameters.add_csv_file( - display_name = "Samples", - variable_name = "samples_csv", - description = "Asp/ disp volumes." + display_name="Samples", + variable_name="samples_csv", + description="Asp/ disp volumes.", ) -def run(ctx: ProtocolContext)-> None: - """Protocol.""" - pipette_mount = ctx.params.pipette_mount - disposable_lid = ctx.params.disposable_lid - csv_samp = ctx.params.samples_csv +def run(ctx: ProtocolContext) -> None: + """Protocol.""" + pipette_mount = ctx.params.pipette_mount # type: ignore[attr-defined] + disposable_lid = ctx.params.disposable_lid # type: ignore[attr-defined] + parsed_csv = ctx.params.csv_data.parse_as_csv() # type: ignore[attr-defined] + rxn_vol = 50 real_mode = True # DECK SETUP AND LABWARE - tc_mod: ThermocyclerContext = ctx.load_module('thermocyclerModuleV2') + tc_mod: ThermocyclerContext = ctx.load_module( + "thermocyclerModuleV2" + ) # type: ignore[assignment] tc_mod.open_lid() tc_mod.set_lid_temperature(105) - temp_mod: TemperatureModuleContext = ctx.load_module('temperature module gen2', location='D3') + temp_mod: TemperatureModuleContext = ctx.load_module( + "temperature module gen2", location="D3" + ) # type: ignore[assignment] reagent_rack = temp_mod.load_labware( - 'opentrons_24_aluminumblock_nest_1.5ml_snapcap') # check if 2mL + "opentrons_24_aluminumblock_nest_1.5ml_snapcap" + ) # check if 2mL - dest_plate = tc_mod.load_labware('opentrons_96_wellplate_200ul_pcr_full_skirt') # do I change this to tough plate if they run pcr? + dest_plate = tc_mod.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt" + ) # do I change this to tough plate if they run pcr? - source_plate = ctx.load_labware('opentrons_96_wellplate_200ul_pcr_full_skirt', location="D1") # do I change this to their plate? + source_plate = ctx.load_labware( + "opentrons_96_wellplate_200ul_pcr_full_skirt", location="D1" + ) # do I change this to their plate? + + tiprack_50 = [ + ctx.load_labware("opentrons_flex_96_tiprack_50ul", slot) for slot in [8, 9] + ] - tiprack_50 = [ctx.load_labware('opentrons_flex_96_tiprack_50ul', slot) for slot in [8, 9]] - # Opentrons tough pcr auto sealing lids if disposable_lid: - unused_lids = [ctx.load_labware("opentrons_tough_pcr_auto_sealing_lid", "C3")] - for i in range(2): - unused_lids.append(unused_lids[-1].load_labware("opentrons_tough_pcr_auto_sealing_lid")) - unused_lids.reverse() - used_lids = [] + unused_lids = helpers.load_disposable_lids(ctx, 3, ["C3"]) + used_lids: List[Labware] = [] # LOAD PIPETTES p50 = ctx.load_instrument( - "flex_8channel_50", pipette_mount, tip_racks=tiprack_50, liquid_presence_detection = True) - p50.configure_nozzle_layout( - style=SINGLE, - start="A1", - tip_racks=tiprack_50) + "flex_8channel_50", + pipette_mount, + tip_racks=tiprack_50, + liquid_presence_detection=True, + ) + p50.configure_nozzle_layout(style=SINGLE, start="A1", tip_racks=tiprack_50) ctx.load_trash_bin("A3") - ctx.define_liquid(name="Mastermix", description='Mastermix', display_color='#008000') - ctx.define_liquid(name="Water", description='Water', display_color='#A52A2A') - ctx.define_liquid(name="DNA", description='DNA', display_color='#A52A2A') + mmx_liq = ctx.define_liquid( + name="Mastermix", description="Mastermix", display_color="#008000" + ) + water_liq = ctx.define_liquid( + name="Water", description="Water", display_color="#A52A2A" + ) + dna_liq = ctx.define_liquid(name="DNA", description="DNA", display_color="#A52A2A") # mapping - csv_lines = [[val.strip() for val in line.split(',')] - for line in csv_samp.splitlines() - if line.split(',')[0].strip()][1:] - temp_mod.set_temperature(4) - - water = reagent_rack['B1'] + water = reagent_rack["B1"] water.load_liquid(liquid=water_liq, volume=1500) # mmx_pic = reagent_rack.rows()[0] for mmx_well in mmx_pic: mmx_well.load_liquid(liquid=mmx_liq, volume=1500) - + dna_pic = source_plate.wells() for dna_well in dna_pic: dna_well.load_liquid(liquid=dna_liq, volume=50) # adding water - ctx.comment('\n\n----------ADDING WATER----------\n') + ctx.comment("\n\n----------ADDING WATER----------\n") p50.pick_up_tip() # p50.aspirate(40, water) # prewet # p50.dispense(40, water) - for row in csv_lines: + num_of_rows = len(parsed_csv) + for row in range(num_of_rows): water_vol = row[1] - if water_vol.lower() == 'x': + if water_vol.lower() == "x": continue water_vol = int(row[1]) dest_well = row[0] @@ -111,14 +121,14 @@ def run(ctx: ProtocolContext)-> None: p50.configure_for_volume(50) # p50.blow_out() - p50.drop_tip() + p50.drop_tip() # adding Mastermix - ctx.comment('\n\n----------ADDING MASTERMIX----------\n') + ctx.comment("\n\n----------ADDING MASTERMIX----------\n") for i, row in enumerate(csv_lines): p50.pick_up_tip() mmx_vol = row[3] - if mmx_vol.lower() == 'x': + if mmx_vol.lower() == "x": continue if i == 0: @@ -127,7 +137,7 @@ def run(ctx: ProtocolContext)-> None: mmx_tube = row[4] if mmx_tube_check != mmx_tube: - p50.drop_tip() + p50.drop_tip() p50.pick_up_tip() if not p50.has_tip: @@ -148,14 +158,14 @@ def run(ctx: ProtocolContext)-> None: p50.drop_tip() if p50.has_tip: - p50.drop_tip() + p50.drop_tip() # adding DNA - ctx.comment('\n\n----------ADDING DNA----------\n') + ctx.comment("\n\n----------ADDING DNA----------\n") for row in csv_lines: dna_vol = row[2] - if dna_vol.lower() == 'x': + if dna_vol.lower() == "x": continue p50.pick_up_tip() @@ -163,35 +173,37 @@ def run(ctx: ProtocolContext)-> None: dna_vol = int(row[2]) dest_and_source_well = row[0] - if dna_vol == 0: break p50.configure_for_volume(dna_vol) p50.aspirate(dna_vol, source_plate[dest_and_source_well]) p50.dispense(dna_vol, dest_plate[dest_and_source_well], rate=0.5) - p50.mix(10, 0.7*rxn_vol if 0.7*rxn_vol < 30 else 30, dest_plate[dest_and_source_well]) - p50.drop_tip() + p50.mix( + 10, + 0.7 * rxn_vol if 0.7 * rxn_vol < 30 else 30, + dest_plate[dest_and_source_well], + ) + p50.drop_tip() p50.configure_for_volume(50) - ctx.comment('\n\n-----------Running PCR------------\n') + ctx.comment("\n\n-----------Running PCR------------\n") if real_mode: profile1: List[ThermocyclerStep] = [ - {'temperature': 95, 'hold_time_minutes': 2}, + {"temperature": 95, "hold_time_minutes": 2}, ] profile2: List[ThermocyclerStep] = [ - - {'temperature': 98, 'hold_time_seconds': 10}, - {'temperature': 58, 'hold_time_seconds': 10}, - {'temperature': 72, 'hold_time_seconds': 30} - ] - profile3: List[ThermocyclerStep] = [ - {'temperature': 72, 'hold_time_minutes': 5} + {"temperature": 98, "hold_time_seconds": 10}, + {"temperature": 58, "hold_time_seconds": 10}, + {"temperature": 72, "hold_time_seconds": 30}, ] + profile3: List[ThermocyclerStep] = [{"temperature": 72, "hold_time_minutes": 5}] if disposable_lid: - lid_on_plate, unused_lids, used_lids = helpers.use_disposable_lid_with_tc(ctx, unused_lids, used_lids, dest_plate, tc_mod) + lid_on_plate, unused_lids, used_lids = helpers.use_disposable_lid_with_tc( + ctx, unused_lids, used_lids, dest_plate, tc_mod + ) else: tc_mod.close_lid() tc_mod.execute_profile(steps=profile1, repetitions=1, block_max_volume=50) @@ -201,7 +213,7 @@ def run(ctx: ProtocolContext)-> None: tc_mod.open_lid() if disposable_lid: - if len(used_lids) <= 1: - ctx.move_labware(lid_on_plate, "C2", use_gripper = True) + if len(used_lids) <= 1: + ctx.move_labware(lid_on_plate, "C2", use_gripper=True) else: - ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper = True) + ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) diff --git a/abr-testing/abr_testing/protocols/helpers.py b/abr-testing/abr_testing/protocols/helpers.py index 64e44df4685..6393ec9f1f9 100644 --- a/abr-testing/abr_testing/protocols/helpers.py +++ b/abr-testing/abr_testing/protocols/helpers.py @@ -13,7 +13,7 @@ ThermocyclerContext, ) -from typing import List, Union +from typing import List def load_common_liquid_setup_labware_and_instruments( @@ -159,9 +159,11 @@ def load_disposable_lids( unused_lids[-1].load_labware("opentrons_tough_pcr_auto_sealing_lid") ) else: - for i in range(len(deck_slot)-1): + for i in range(len(deck_slot) - 1): unused_lids.append( - protocol.load_labware("opentrons_tough_pcr_auto_sealing_lid", deck_slot[i]) + protocol.load_labware( + "opentrons_tough_pcr_auto_sealing_lid", deck_slot[i] + ) ) unused_lids.reverse() return unused_lids diff --git a/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py b/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py index e1707a4113b..63e40519fac 100644 --- a/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py +++ b/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py @@ -1,5 +1,4 @@ """Protocol to Test the Stacking and Movement of Tough Auto Seal Lid.""" -from typing import List, Union from opentrons.protocol_api import ( ParameterContext, ProtocolContext, @@ -11,7 +10,7 @@ from abr_testing.protocols import helpers -metadata = {"protocolName": "Flat and Stacked Offset TC Lid Testing"} +metadata = {"protocolName": "5 Stack Test"} requirements = {"robotType": "Flex", "apiLevel": "2.20"} @@ -20,47 +19,56 @@ def add_parameters(parameters: ParameterContext) -> None: parameters.add_int( variable_name="lids_in_a_stack", display_name="Num of Lids in Stack", - minimum = 1, - maximum = 5, - default = 1 + minimum=1, + maximum=5, + default=5, ) parameters.add_float( - variable_name = "x_offset", - display_name= "X Offset", + variable_name="x_offset", + display_name="X Offset", choices=[ - {"display_name": "-1.4", "value": -1.4}, - {"display_name": "-1.3", "value": -1.3}, - {"display_name": "-1.2", "value": -1.2}, - {"display_name": "-1.1", "value": -1.1}, - {"display_name": "-1", "value": -1}, - {"display_name": "-0.9", "value": -0.9}, - {"display_name": "-0.8", "value": -0.8}, - {"display_name": "-0.7", "value": -0.7}, - {"display_name": "-0.6", "value": -0.6}, - {"display_name": "-0.5", "value": -0.5}, - {"display_name": "-0.4", "value": -0.4}, - {"display_name": "-0.3", "value": -0.3}, - {"display_name": "-0.2", "value": -0.2}, - {"display_name": "-0.1", "value": -0.1}, {"display_name": "0.0", "value": 0.0}, - {"display_name": "-0.1", "value": 0.1}, - {"display_name": "-0.1", "value": 0.2}, - {"display_name": "-0.1", "value": 0.3}, - {"display_name": "-0.1", "value": 0.4}, - {"display_name": "-0.1", "value": 0.5}, + {"display_name": "0.1", "value": 0.1}, + {"display_name": "0.2", "value": 0.2}, + {"display_name": "0.3", "value": 0.3}, + {"display_name": "0.4", "value": 0.4}, + {"display_name": "0.5", "value": 0.5}, + {"display_name": "0.6", "value": 0.6}, + {"display_name": "0.7", "value": 0.7}, + {"display_name": "0.8", "value": 0.8}, + {"display_name": "0.9", "value": 0.9}, + {"display_name": "1.0", "value": 1.0}, + {"display_name": "1.1", "value": 1.1}, + {"display_name": "1.2", "value": 1.2}, + {"display_name": "1.3", "value": 1.3}, + {"display_name": "1.4", "value": 1.4}, {"display_name": "1.5", "value": 1.5}, {"display_name": "1.6", "value": 1.6}, {"display_name": "1.7", "value": 1.7}, {"display_name": "1.8", "value": 1.8}, + {"display_name": "1.9", "value": 1.9}, + {"display_name": "2", "value": 2}, + + ], - default = 0.0 + default=2, ) + parameters.add_bool( + variable_name = "negative", + display_name = "Negative", + description = "Turn on to make offset negative.", + default = False + ) + def run(protocol: ProtocolContext) -> None: """Runs protocol that moves lids and stacks them.""" # Load Parameters lids_in_stack = protocol.params.lids_in_a_stack # type: ignore[attr-defined] - x_offset = protocol.params.x_offset # type: ignore[attr-defined] + x_offset = protocol.params.x_offset # type: ignore[attr-defined] + negative = protocol.params.negative # type: ignore[attr-defined] + if negative: + x_offset = x_offset * -1 # Thermocycler thermocycler: ThermocyclerContext = protocol.load_module( "thermocyclerModuleV2" @@ -70,28 +78,23 @@ def run(protocol: ProtocolContext) -> None: ) thermocycler.open_lid() # Load Lids - if lids_in_stack == 1: - slot_locations = ["D2", "C2", "B2", "C3", "B3"] - else: - slot_locations = ["D2"] - lids = helpers.load_disposable_lids(protocol, lids_in_stack, slot_locations) + lid_stack_1 = helpers.load_disposable_lids(protocol, lids_in_stack, ["D2"]) + lid_stack_2 = helpers.load_disposable_lids(protocol, lids_in_stack, ["C2"]) + lid_stack_3 = helpers.load_disposable_lids(protocol, lids_in_stack, ["B2"]) + lid_stack_4 = helpers.load_disposable_lids(protocol, lids_in_stack, ["C3"]) + lid_stack_5 = helpers.load_disposable_lids(protocol, lids_in_stack, ["B3"]) + drop_offset = {"x": x_offset, "y": 0, "z": 0} slot = 0 - for lid in lids: - protocol.comment( - f"Offset {x_offset}, Lid # {slot+1}" - ) + lids = [lid_stack_1, lid_stack_2, lid_stack_3, lid_stack_4, lid_stack_5] + for lid_list in lids: + lid_to_move = lid_list[0] + + lid_to_move_back_to = lid_list[1] + protocol.comment(f"Offset {x_offset}, Lid # {slot+1}") # move lid to plate in thermocycler protocol.move_labware( - lid, plate_in_cycler, use_gripper=True, drop_offset=drop_offset + lid_to_move, plate_in_cycler, use_gripper=True, drop_offset=drop_offset ) - - if slot == 0: - move_location = "C1" - else: - move_location = prev_moved_lid - - protocol.move_labware(lid, move_location, use_gripper=True) - slot +=1 - prev_moved_lid = lid - + protocol.move_labware(lid_to_move, lid_to_move_back_to, use_gripper=True) + From 8ba70e990ee7194a6dff2f72d097eac9896fc369 Mon Sep 17 00:00:00 2001 From: rclarke0 Date: Thu, 7 Nov 2024 15:15:57 -0500 Subject: [PATCH 07/13] abr protocols and liquid set ups --- .../10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py | 143 +-- .../11_Dynabeads_IP_Flex_96well_RIT.py | 46 +- .../12_KAPA HyperPlus Library Prep.py | 192 ++- .../1_Simple Normalize Long Right.py | 356 ++++++ .../2_BMS_PCR_Protocol.py} | 109 +- .../3_OT3 ABR Normalize with Tubes.py | 344 +++++ ...omplex protocol with single tip Pick Up.py | 38 +- .../7_HDQ_DNA_Bacteria_Flex.py | 131 +- .../8_Illumina and Plate Reader.py | 949 ++++++++++++++ .../9_Magmax_RNA_Cells_Flex.py} | 123 +- .../protocols/csv_parameters/3_samplevols.csv | 25 + .../hellma_reference_plate.json | 1127 +++++++++++++++++ abr-testing/abr_testing/protocols/helpers.py | 320 ++++- .../10_ZymoBIOMICS Magbead Liquid Setup.py | 6 +- .../11_Dynabeads RIT Liquid Setup.py | 6 +- ...APA HyperPlus Library Prep Liquid Setup.py | 6 +- .../1_Simple normalize long Liquid Setup.py | 6 +- .../2_BMS_PCR_protocol Liquid Setup.py | 26 +- ...3 ABR Normalize with Tubes Liquid Setup.py | 40 + .../4_Illumina DNA Enrichment Liquid Setup.py | 10 +- .../5_96ch Complex Protocol Liquid Setup.py | 6 +- ...DQ DNA Bacteria Extraction Liquid Setup.py | 6 +- ...ermo MagMax RNA Extraction Liquid Setup.py | 6 +- .../test_protocols/tc_lid_x_offset_test.py | 18 +- 24 files changed, 3481 insertions(+), 558 deletions(-) rename abr-testing/abr_testing/protocols/{api 2.20 => active_protocols}/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py (84%) rename abr-testing/abr_testing/protocols/{api 2.20 => active_protocols}/11_Dynabeads_IP_Flex_96well_RIT.py (83%) rename abr-testing/abr_testing/protocols/{api 2.20 => active_protocols}/12_KAPA HyperPlus Library Prep.py (91%) create mode 100644 abr-testing/abr_testing/protocols/active_protocols/1_Simple Normalize Long Right.py rename abr-testing/abr_testing/protocols/{api 2.20/bms_pcr_protocol_220api.py => active_protocols/2_BMS_PCR_Protocol.py} (66%) create mode 100644 abr-testing/abr_testing/protocols/active_protocols/3_OT3 ABR Normalize with Tubes.py rename abr-testing/abr_testing/protocols/{api 2.20 => active_protocols}/5_96ch complex protocol with single tip Pick Up.py (92%) rename abr-testing/abr_testing/protocols/{api 2.20 => active_protocols}/7_HDQ_DNA_Bacteria_Flex.py (83%) create mode 100644 abr-testing/abr_testing/protocols/active_protocols/8_Illumina and Plate Reader.py rename abr-testing/abr_testing/protocols/{api 2.20/9_Magmax_RNA_Cells_Flex_csv.py => active_protocols/9_Magmax_RNA_Cells_Flex.py} (85%) create mode 100644 abr-testing/abr_testing/protocols/csv_parameters/3_samplevols.csv create mode 100644 abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json create mode 100644 abr-testing/abr_testing/protocols/liquid_setups/3_OT3 ABR Normalize with Tubes Liquid Setup.py diff --git a/abr-testing/abr_testing/protocols/api 2.20/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py b/abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py similarity index 84% rename from abr-testing/abr_testing/protocols/api 2.20/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py rename to abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py index 75c3af5b665..e193869179d 100644 --- a/abr-testing/abr_testing/protocols/api 2.20/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py +++ b/abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py @@ -1,7 +1,7 @@ """Flex ZymoBIOMICS Magbead DNA Extraction: Cells.""" import math from opentrons import types -from typing import List, Union +from typing import List, Dict from opentrons import protocol_api from opentrons.protocol_api import Well, InstrumentContext import numpy as np @@ -51,7 +51,7 @@ def add_parameters(parameters: protocol_api.ParameterContext) -> None: """Define parameters.""" helpers.create_hs_speed_parameter(parameters) - helpers.create_pipette_mount_parameter(parameters) + helpers.create_single_pipette_mount_parameter(parameters) helpers.create_dot_bottom_parameter(parameters) @@ -100,25 +100,23 @@ def run(ctx: protocol_api.ProtocolContext) -> None: binding_buffer_vol = bind_vol + bead_vol ctx.load_trash_bin("A3") h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] - h_s_adapter = h_s.load_adapter("opentrons_96_deep_well_adapter") - sample_plate = h_s_adapter.load_labware(deepwell_type, "Samples") + labware_name = "Samples" + sample_plate, h_s_adapter = helpers.load_hs_adapter_and_labware( + deepwell_type, h_s, labware_name + ) h_s.close_labware_latch() temp: TemperatureModuleContext = ctx.load_module( helpers.temp_str, "D3" ) # type: ignore[assignment] - temp_block = temp.load_adapter("opentrons_96_well_aluminum_block") - elutionplate = temp_block.load_labware( - "opentrons_96_wellplate_200ul_pcr_full_skirt", "Elution Plate" + elutionplate, temp_adapter = helpers.load_temp_adapter_and_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", temp, "Elution Plate" ) magblock: MagneticBlockContext = ctx.load_module( helpers.mag_str, "C1" ) # type: ignore[assignment] - waste = ( - ctx.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") - .wells()[0] - .top() - ) + waste_reservoir = ctx.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") + waste = waste_reservoir.wells()[0].top() res1 = ctx.load_labware(res_type, "D2", "reagent reservoir 1") res2 = ctx.load_labware(res_type, "C2", "reagent reservoir 2") num_cols = math.ceil(num_samples / 8) @@ -130,7 +128,9 @@ def run(ctx: protocol_api.ProtocolContext) -> None: tips = [*tips1000.wells()[num_samples:96], *tips1001.wells(), *tips1002.wells()] tips_sn = tips1000.wells()[:num_samples] # load instruments - m1000 = ctx.load_instrument("flex_8channel_1000", mount) + m1000 = ctx.load_instrument( + "flex_8channel_1000", mount, tip_racks=[tips1000, tips1001, tips1002] + ) """ Here is where you can define the locations of your reagents. @@ -148,100 +148,21 @@ def run(ctx: protocol_api.ProtocolContext) -> None: # Redefine per well for liquid definitions samps = sample_plate.wells()[: (8 * num_cols)] - colors = helpers.liquid_colors - - locations: List[Union[List[Well], Well]] = [ - lysis_, - lysis_, - binding_buffer, - binding_buffer, - bind2_res, - wash1, - wash2, - wash3, - elution_solution, - ] - vols = [ - lysis_vol, - PK_vol, - bead_vol, - bind_vol, - bind2_vol, - wash1_vol, - wash2_vol, - wash3_vol, - elution_vol, - ] - liquids = [ - "Lysis", - "PK", - "Beads", - "Binding", - "Binding 2", - "Wash 1", - "Wash 2", - "Wash 3", - "Final Elution", - ] - - # Defining liquids per sample well - samples = ctx.define_liquid( - name="Samples", description="Samples", display_color="#C0C0C0" + liquid_vols_and_wells: Dict[str, List[Dict[str, Well | List[Well] | float]]] = { + "Lysis": [{"well": lysis_, "volume": lysis_vol}], + "PK": [{"well": lysis_, "volume": PK_vol}], + "Beads": [{"well": binding_buffer, "volume": bead_vol}], + "Binding": [{"well": binding_buffer, "volume": bind_vol}], + "Binding 2": [{"well": bind2_res, "volume": bind2_vol}], + "Wash 1": [{"well": wash1_vol, "volume": wash1}], + "Wash 2": [{"well": wash2_vol, "volume": wash2}], + "Wash 3": [{"well": wash3_vol, "volume": wash3}], + "Final Elution": [{"well": elution_solution, "volume": elution_vol}], + "Samples": [{"well": samps, "volume": 0}], + } + flattened_list_of_wells = helpers.find_liquid_height_of_loaded_liquids( + ctx, liquid_vols_and_wells, m1000 ) - for i in samps: - i.load_liquid(liquid=samples, volume=0) - - delete = len(colors) - len(liquids) - - if delete >= 1: - for i_del in range(delete): - colors.pop(-1) - - def add_liquid( - liq_type: str, wells: Union[Well, List[Well]], color: str, vol: float - ) -> None: - """Assigns colored liquid to wells based on type and location.""" - total_samples = math.ceil(num_samples / 8) * 8 - - # Calculate extra sample volume based on liquid type - extra_samples = math.ceil( - 1500 - / ( - lysis_vol - if liq_type == "PK" - else bind_vol - if liq_type == "Beads" - else vol - ) - ) - - # Define liquid - liquid = ctx.define_liquid( - name=liq_type, description=liq_type, display_color=color - ) - - # Assign liquid to each well - if isinstance(wells, list): - samples_per_well = [sample_max // len(wells)] * ( - total_samples // (sample_max // len(wells)) - ) - remainder = total_samples % (sample_max // len(wells)) - - if remainder: - samples_per_well.append(remainder) - - for sample_count, well in zip(samples_per_well, wells): - well.load_liquid( - liquid=liquid, volume=vol * (sample_count + extra_samples) - ) - else: - wells.load_liquid( - liquid=liquid, volume=vol * (total_samples + extra_samples) - ) - - # Apply function for each liquid configuration - for liq, well, color, vol in zip(liquids, locations, colors, vols): - add_liquid(liq, well, color, vol) m1000.flow_rate.aspirate = 300 m1000.flow_rate.dispense = 300 @@ -447,7 +368,7 @@ def bind(vol1: float, vol2: float) -> None: helpers.set_hs_speed(ctx, h_s, heater_shaker_speed * 0.9, bind_time_1, True) # Transfer from H-S plate to Magdeck plate - helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) for bindi in np.arange( settling_time + 1, 0, -0.5 @@ -494,7 +415,7 @@ def bind(vol1: float, vol2: float) -> None: helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, bind_time_2, True) # Transfer from H-S plate to Magdeck plate - helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) for bindi in np.arange( settling_time + 1, 0, -0.5 @@ -550,7 +471,7 @@ def wash(vol: float, source: List[Well]) -> None: m1000.drop_tip() if TIP_TRASH else m1000.return_tip() helpers.set_hs_speed(ctx, h_s, heater_shaker_speed * 0.9, wash_time, True) - helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) for washi in np.arange( settling_time, 0, -0.5 @@ -578,7 +499,7 @@ def elute(vol: float) -> None: helpers.set_hs_speed(ctx, h_s, heater_shaker_speed * 0.9, wash_time, True) # Transfer back to magnet - helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) for elutei in np.arange(settling_time, 0, -0.5): ctx.delay( @@ -616,3 +537,5 @@ def elute(vol: float) -> None: ) elute(elution_vol) h_s.deactivate_heater() + flattened_list_of_wells.extend([waste_reservoir["A1"], elutionplate["A1"]]) + helpers.find_liquid_height_of_all_wells(ctx, m1000, flattened_list_of_wells) diff --git a/abr-testing/abr_testing/protocols/api 2.20/11_Dynabeads_IP_Flex_96well_RIT.py b/abr-testing/abr_testing/protocols/active_protocols/11_Dynabeads_IP_Flex_96well_RIT.py similarity index 83% rename from abr-testing/abr_testing/protocols/api 2.20/11_Dynabeads_IP_Flex_96well_RIT.py rename to abr-testing/abr_testing/protocols/active_protocols/11_Dynabeads_IP_Flex_96well_RIT.py index 5762c0e3f1f..dec881f9199 100644 --- a/abr-testing/abr_testing/protocols/api 2.20/11_Dynabeads_IP_Flex_96well_RIT.py +++ b/abr-testing/abr_testing/protocols/active_protocols/11_Dynabeads_IP_Flex_96well_RIT.py @@ -6,7 +6,7 @@ MagneticBlockContext, ) from abr_testing.protocols import helpers -from typing import List, Union +from typing import List, Dict, Union metadata = { "protocolName": "Immunoprecipitation by Dynabeads - (Reagents in 15 mL tubes)", @@ -23,7 +23,7 @@ def add_parameters(parameters: ParameterContext) -> None: """Define parameters.""" helpers.create_hs_speed_parameter(parameters) - helpers.create_pipette_mount_parameter(parameters) + helpers.create_two_pipette_mount_parameters(parameters) helpers.create_dot_bottom_parameter(parameters) @@ -53,6 +53,8 @@ def run(ctx: ProtocolContext) -> None: # defining variables inside def run heater_shaker_speed = ctx.params.heater_shaker_speed # type: ignore[attr-defined] ASP_HEIGHT = ctx.params.dot_bottom # type: ignore[attr-defined] + single_channel_mount = ctx.params.pipette_mount_1 # type: ignore[attr-defined] + eight_channel_mount = ctx.params.pipette_mount_2 # type: ignore[attr-defined] MIX_SPEED = heater_shaker_speed MIX_SEC = 10 @@ -82,20 +84,23 @@ def run(ctx: ProtocolContext) -> None: "opentrons_flex_96_tiprack_1000ul", "C2", "reused tips" ) tips_reused_loc = tips_reused.wells()[:95] - p1000 = ctx.load_instrument("flex_8channel_1000", "right", tip_racks=[tips]) - p1000_single = ctx.load_instrument("flex_1channel_1000", "left", tip_racks=[tips]) + p1000 = ctx.load_instrument( + "flex_8channel_1000", eight_channel_mount, tip_racks=[tips] + ) + p1000_single = ctx.load_instrument( + "flex_1channel_1000", single_channel_mount, tip_racks=[tips] + ) h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] - h_s_adapter = h_s.load_adapter("opentrons_96_deep_well_adapter") - working_plate = h_s_adapter.load_labware( - "nest_96_wellplate_2ml_deep", "working plate" + working_plate, h_s_adapter = helpers.load_hs_adapter_and_labware( + "nest_96_wellplate_2ml_deep", h_s, "Working Plate" ) if READY_FOR_SDSPAGE == 0: temp: TemperatureModuleContext = ctx.load_module( helpers.temp_str, "D3" ) # type: ignore[assignment] - final_plate = temp.load_labware( - "opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep", "final plate" + final_plate, temp_adapter = helpers.load_temp_adapter_and_labware( + "nest_96_wellplate_2ml_deep", temp, "Final Plate" ) mag: MagneticBlockContext = ctx.load_module(helpers.mag_str, "C1") # type: ignore[assignment] @@ -110,6 +115,19 @@ def run(ctx: ProtocolContext) -> None: working_wells = working_plate.wells()[: NUM_COL * 8] # 6 if READY_FOR_SDSPAGE == 0: final_cols = final_plate.rows()[0][:NUM_COL] + # Define Liquids + liquid_vols_and_wells: Dict[ + str, List[Dict[str, Union[Well, List[Well], float]]] + ] = { + "Beads": [{"well": beads, "volume": 4900}], + "AB": [{"well": ab, "volume": 4900}], + "Elution": [{"well": elu, "volume": 4900}], + "Wash": [{"well": wash, "volume": 750}], + "Samples": [{"well": samples, "volume": 250}], + } + flattened_wells = helpers.find_liquid_height_of_loaded_liquids( + ctx, liquid_vols_and_wells, p1000_single + ) def transfer_plate_to_plate( vol1: float, start: List[Well], end: List[Well], liquid: int @@ -197,7 +215,7 @@ def discard(vol3: float, start: List[Well]) -> None: h_s.close_labware_latch() transfer_well_to_plate(BEADS_VOL, beads, working_wells, 2) - helpers.move_labware_from_hs_to_mag_block(ctx, working_plate, h_s, mag) + helpers.move_labware_from_hs_to_destination(ctx, working_plate, h_s, mag) ctx.delay(minutes=MAG_DELAY_MIN) discard(BEADS_VOL * 1.1, working_cols) @@ -214,7 +232,7 @@ def discard(vol3: float, start: List[Well]) -> None: ctx.delay(seconds=INCUBATION_MIN * 60) h_s.deactivate_shaker() - helpers.move_labware_from_hs_to_mag_block(ctx, working_plate, h_s, mag) + helpers.move_labware_from_hs_to_destination(ctx, working_plate, h_s, mag) ctx.delay(minutes=MAG_DELAY_MIN) vol_total = SAMPLE_VOL + AB_VOL @@ -226,7 +244,7 @@ def discard(vol3: float, start: List[Well]) -> None: transfer_well_to_plate(WASH_VOL, wash, working_cols, 5) helpers.set_hs_speed(ctx, h_s, MIX_SPEED, MIX_SEC / 60, True) - helpers.move_labware_from_hs_to_mag_block(ctx, working_plate, h_s, mag) + helpers.move_labware_from_hs_to_destination(ctx, working_plate, h_s, mag) ctx.delay(minutes=MAG_DELAY_MIN) discard(WASH_VOL * 1.1, working_cols) @@ -246,7 +264,9 @@ def discard(vol3: float, start: List[Well]) -> None: helpers.set_hs_speed(ctx, h_s, MIX_SPEED, (MIX_SEC / 60) + 2, True) temp.set_temperature(4) - helpers.move_labware_from_hs_to_mag_block(ctx, working_plate, h_s, mag) + helpers.move_labware_from_hs_to_destination(ctx, working_plate, h_s, mag) ctx.delay(minutes=MAG_DELAY_MIN) transfer_plate_to_plate(ELUTION_VOL * 1.1, working_cols, final_cols, 6) temp.deactivate() + flattened_wells.append(waste) + helpers.find_liquid_height_of_all_wells(ctx, p1000_single, flattened_wells) diff --git a/abr-testing/abr_testing/protocols/api 2.20/12_KAPA HyperPlus Library Prep.py b/abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py similarity index 91% rename from abr-testing/abr_testing/protocols/api 2.20/12_KAPA HyperPlus Library Prep.py rename to abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py index 4f9fe05d976..3488e898dd9 100644 --- a/abr-testing/abr_testing/protocols/api 2.20/12_KAPA HyperPlus Library Prep.py +++ b/abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py @@ -14,7 +14,6 @@ MagneticBlockContext, ThermocyclerContext, ) -from opentrons.hardware_control.modules.types import ThermocyclerStep from typing import List, Tuple, Optional metadata = { @@ -51,6 +50,7 @@ def add_parameters(parameters: ParameterContext) -> None: default=False, ) helpers.create_disposable_lid_parameter(parameters) + helpers.create_two_pipette_mount_parameters(parameters) parameters.add_int( variable_name="num_samples", display_name="number of samples", @@ -83,6 +83,8 @@ def run(ctx: ProtocolContext) -> None: USE_GRIPPER = True trash_tips = ctx.params.trash_tips # type: ignore[attr-defined] dry_run = ctx.params.dry_run # type: ignore[attr-defined] + pipette_1000_mount = ctx.params.pipette_mount_1 # type: ignore[attr-defined] + pipette_50_mount = ctx.params.pipette_mount_2 # type: ignore[attr-defined] REUSE_ETOH_TIPS = False REUSE_RSB_TIPS = ( False # Reuse tips for RSB buffer (adding RSB, mixing, and transferring) @@ -124,9 +126,10 @@ def run(ctx: ProtocolContext) -> None: temp_mod: TemperatureModuleContext = ctx.load_module( helpers.temp_str, "B3" ) # type: ignore[assignment] - temp_adapter = temp_mod.load_adapter("opentrons_96_well_aluminum_block") - temp_plate = temp_adapter.load_labware( - "opentrons_96_wellplate_200ul_pcr_full_skirt", "Temp Module Reservoir Plate" + temp_plate, temp_adapter = helpers.load_temp_adapter_and_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", + temp_mod, + "Temp Module Reservoir Plate", ) if not dry_run: @@ -163,8 +166,8 @@ def run(ctx: ProtocolContext) -> None: global tt_50 global tt_200 - p200 = ctx.load_instrument("flex_8channel_1000", "left") - p50 = ctx.load_instrument("flex_8channel_50", "right") + p200 = ctx.load_instrument("flex_8channel_1000", pipette_1000_mount) + p50 = ctx.load_instrument("flex_8channel_50", pipette_50_mount) Available_on_deck_slots = ["A2", "A3", "B3"] Available_off_deck_slots = ["A4", "B4"] @@ -198,114 +201,76 @@ def run(ctx: ProtocolContext) -> None: p200.starting_tip = tip200_reuse.wells()[(len(RemoveSup_tip)) * 8] # Load Reagent Locations in Reservoirs - - # Sample Plate - sample_liq = ctx.define_liquid( - name="Samples", - description="DNA sample of known quantity", - display_color="#C0C0C0", - ) - for well in sample_plate.wells()[: 8 * num_cols]: - well.load_liquid(liquid=sample_liq, volume=sample_vol) - - Final_liq = ctx.define_liquid( - name="Final Library", description="Final Library", display_color="#FFA500" - ) - for well in sample_plate_2.wells()[: 8 * num_cols]: - well.load_liquid(liquid=Final_liq, volume=elution_vol_2) - - # Cold Res - + lib_amplification_wells: List[Well] = temp_plate.columns()[num_cols + 3] + amplification_res = lib_amplification_wells[0] adapters = temp_plate.rows()[0][:num_cols] # used for filling liquids - adapter_liq = ctx.define_liquid( - name="Adapters", - description="Adapters to ligate onto DNA insert.", - display_color="#A52A2A", - ) - for well in temp_plate.wells()[: 8 * num_cols]: - well.load_liquid(liquid=adapter_liq, volume=adapter_vol * 2) - end_repair_cols: List[Well] = temp_plate.columns()[ num_cols ] # used for filling liquids er_res = end_repair_cols[0] - er_liq = ctx.define_liquid( - name="End Repair", description="End Repair mix", display_color="#FF00FF" - ) - for well in end_repair_cols: - well.load_liquid( - liquid=er_liq, volume=(end_repair_vol * num_cols) + (0.1 * end_repair_vol) - ) - frag: List[Well] = temp_plate.columns()[num_cols + 1] frag_res = frag[0] - frag_liq = ctx.define_liquid( - name="Fragmentation", description="Fragmentation mix", display_color="#00FFFF" - ) - for well in frag: - well.load_liquid( - liquid=frag_liq, volume=(frag_vol * num_cols) + (0.1 * frag_vol) - ) - ligation: List[Well] = temp_plate.columns()[num_cols + 2] ligation_res = ligation[0] - ligation_liq = ctx.define_liquid( - name="Ligation", description="Ligation Mix", display_color="#008000" - ) - for well in ligation: - well.load_liquid( - liquid=ligation_liq, volume=(ligation_vol * num_cols) + (0.1 * ligation_vol) - ) - - lib_amplification_wells: List[Well] = temp_plate.columns()[num_cols + 3] - amplification_res = lib_amplification_wells[0] - amp_liq = ctx.define_liquid( - name="Amplification", description="Amplification Mix", display_color="#0000FF" - ) - for well in lib_amplification_wells: - well.load_liquid( - liquid=amp_liq, - volume=(amplification_vol * num_cols) + (0.1 * amplification_vol), - ) - # Room Temp Res (deepwell) bead = reservoir.columns()[0] bead_res = bead[0] - bead_liq = ctx.define_liquid( - name="Ampure Beads", description="Ampure Beads", display_color="#800080" - ) - for well in bead: - well.load_liquid( - liquid=bead_liq, volume=(bead_vol * num_cols) + (0.1 * bead_vol * num_cols) - ) - rsb = reservoir.columns()[3] rsb_res = rsb[0] - rsb_liq = ctx.define_liquid( - name="RSB", description="Resuspension buffer", display_color="#FFFF00" - ) - for well in rsb: - well.load_liquid( - liquid=rsb_liq, volume=(rsb_vol * num_cols) + (0.1 * rsb_vol * num_cols) - ) - etoh1 = reservoir.columns()[4] etoh1_res = etoh1[0] - etoh_liq = ctx.define_liquid( - name="Ethanol 80%", description="Fresh 80% Ethanol", display_color="#FF00FF" - ) - for well in etoh1: - well.load_liquid( - liquid=etoh_liq, volume=(etoh_vol * num_cols) + (0.1 * etoh_vol * num_cols) - ) - etoh2 = reservoir.columns()[5] etoh2_res = etoh2[0] - for well in etoh2: - well.load_liquid( - liquid=etoh_liq, volume=(etoh_vol * num_cols) + (0.1 * etoh_vol * num_cols) - ) + liquid_vols_and_wells = { + "Samples": [ + {"well": sample_plate.wells()[: 8 * num_cols], "volume": sample_vol} + ], + "Final Library": [ + {"well": sample_plate_2.wells()[: 8 * num_cols], "volume": elution_vol_2} + ], + "Adapters": [{"well": adapters, "volume": adapter_vol * 2.0}], + "End Repair Mix": [ + { + "well": end_repair_cols, + "volume": (end_repair_vol * num_cols) + (0.1 * end_repair_vol), + } + ], + "Fragmentation Mix": [ + {"well": frag, "volume": (frag_vol * num_cols) + (0.1 * frag_vol)} + ], + "Ligation Mix": [ + { + "well": ligation, + "volume": (ligation_vol * num_cols) + (0.1 * ligation_vol), + } + ], + "Amplification Mix": [ + { + "well": lib_amplification_wells, + "volume": (amplification_vol * num_cols) + (0.1 * amplification_vol), + } + ], + "Ampure Beads": [ + { + "well": bead, + "volume": (bead_vol * num_cols) + (0.1 * bead_vol * num_cols), + } + ], + "Resuspension Buffer": [ + {"well": rsb, "volume": (rsb_vol * num_cols) + (0.1 * rsb_vol * num_cols)} + ], + "Ethanol 80%": [ + { + "well": etoh1, + "volume": (etoh_vol * num_cols) + (0.1 * etoh_vol * num_cols), + }, + { + "well": etoh2, + "volume": (etoh_vol * num_cols) + (0.1 * etoh_vol * num_cols), + }, + ], + } waste1 = reservoir.columns()[6] waste1_res = waste1[0] @@ -660,25 +625,15 @@ def run_amplification_profile( else: tc_mod.close_lid() if not dry_run: - profile_PCR_1: List[ThermocyclerStep] = [ - {"temperature": 98, "hold_time_seconds": 45} - ] - tc_mod.execute_profile( - steps=profile_PCR_1, repetitions=1, block_max_volume=50 - ) - profile_PCR_2: List[ThermocyclerStep] = [ - {"temperature": 98, "hold_time_seconds": 15}, - {"temperature": 60, "hold_time_seconds": 30}, - {"temperature": 72, "hold_time_seconds": 30}, - ] - tc_mod.execute_profile( - steps=profile_PCR_2, repetitions=PCRCYCLES, block_max_volume=50 - ) - profile_PCR_3: List[ThermocyclerStep] = [ - {"temperature": 72, "hold_time_minutes": 1} - ] - tc_mod.execute_profile( - steps=profile_PCR_3, repetitions=1, block_max_volume=50 + helpers.perform_pcr( + ctx, + tc_mod, + initial_denature_time_sec=45, + denaturation_time_sec=15, + anneal_time_sec=30, + extension_time_sec=30, + cycle_repetitions=PCRCYCLES, + final_extension_time_min=1, ) tc_mod.set_block_temperature(4) tc_mod.open_lid() @@ -1246,9 +1201,18 @@ def lib_cleanup_2() -> None: # Set Block Temp for Final Plate tc_mod.set_block_temperature(4) + tiptrack(tip50, None, reuse=False) + p50.return_tip() + probed_wells = helpers.find_liquid_height_of_loaded_liquids( + ctx, liquid_vols_and_wells, p50 + ) + unused_lids, used_lids = Fragmentation(unused_lids, used_lids) unused_lids, used_lids = end_repair(unused_lids, used_lids) unused_lids, used_lids = index_ligation(unused_lids, used_lids) lib_cleanup() unused_lids, used_lids = lib_amplification(unused_lids, used_lids) lib_cleanup_2() + probed_wells.append(waste1_res) + probed_wells.append(waste2_res) + helpers.find_liquid_height_of_all_wells(ctx, p50, probed_wells) diff --git a/abr-testing/abr_testing/protocols/active_protocols/1_Simple Normalize Long Right.py b/abr-testing/abr_testing/protocols/active_protocols/1_Simple Normalize Long Right.py new file mode 100644 index 00000000000..5c63511dac7 --- /dev/null +++ b/abr-testing/abr_testing/protocols/active_protocols/1_Simple Normalize Long Right.py @@ -0,0 +1,356 @@ +"""Simple Normalize Long with LPD and Single Tip.""" +from opentrons.protocol_api import ( + ProtocolContext, + ParameterContext, + Labware, + SINGLE, + InstrumentContext, + Well, +) +from abr_testing.protocols import helpers + +metadata = { + "protocolName": "Simple Normalize Long with LPD and Single Tip", + "author": "Opentrons ", + "source": "Protocol Library", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.20", +} + + +def add_parameters(parameters: ParameterContext) -> None: + """Parameters.""" + helpers.create_single_pipette_mount_parameter(parameters) + helpers.create_tip_size_parameter(parameters) + + +def get_next_tip_by_row(tip_rack: Labware, pipette: InstrumentContext) -> Well | None: + """Get next tip by row. + + This function returns the well name of the next tip to pick up for a given + tiprack with row-bias. Returns None if the pipette is out of tips + """ + if tip_rack.is_tiprack: + if pipette.channels == 8: + for passes in range( + 0, int(len(tip_rack.columns()[0]) / pipette.active_channels) + ): + for column in tip_rack.columns(): + # When the pipette's starting channels is H1, consume tips starting at top row. + if pipette._core.get_nozzle_map().starting_nozzle == "H1": + active_column = column + else: + # We reverse our tiprack reference to consume tips starting at bottom. + active_column = column[::-1] + + if len(active_column) >= ( + ((pipette.active_channels * passes) + pipette.active_channels) + ) and all( + well.has_tip is True + for well in active_column[ + (pipette.active_channels * passes) : ( + ( + (pipette.active_channels * passes) + + pipette.active_channels + ) + ) + ] + ): + return active_column[ + ( + (pipette.active_channels * passes) + + (pipette.active_channels - 1) + ) + ] + # No valid tips were found for current pipette configuration in provided tip rack. + return None + else: + raise ValueError( + "Parameter 'pipette' of get_next_tip_by_row must be an 8 Channel Pipette." + ) + else: + raise ValueError( + "Parameter 'tip_rack' of get_next_tip_by_row must be a recognized Tip Rack labware." + ) + + +def run(protocol: ProtocolContext) -> None: + """Protocol.""" + tip_type = protocol.params.tip_size # type: ignore[attr-defined] + mount_pos = protocol.params.pipette_mount # type: ignore[attr-defined] + # DECK SETUP AND LABWARE + protocol.comment("THIS IS A NO MODULE RUN") + tiprack_x_1 = protocol.load_labware(tip_type, "D1") + tiprack_x_2 = protocol.load_labware(tip_type, "D2") + tiprack_x_3 = protocol.load_labware(tip_type, "B1") + sample_plate_1 = protocol.load_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", "D3" + ) + + reservoir = protocol.load_labware("nest_12_reservoir_15ml", "B3") + sample_plate_2 = protocol.load_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", "C2" + ) + sample_plate_3 = protocol.load_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", "B2" + ) + protocol.load_trash_bin("A3") + + # reagent + Dye_1 = reservoir["A1"] + Dye_2 = reservoir["A2"] + Dye_3 = reservoir["A3"] + Diluent_1 = reservoir["A4"] + Diluent_2 = reservoir["A5"] + + # pipette + p1000 = protocol.load_instrument( + "flex_8channel_1000", mount_pos, liquid_presence_detection=True + ) + # LOAD LIQUIDS + liquid_volumes = [675.0, 675.0, 675.0, 675.0, 675.0] + wells = [Dye_1, Dye_2, Dye_3, Diluent_1, Diluent_2] + helpers.load_wells_with_water(protocol, wells, liquid_volumes) + + current_rack = tiprack_x_1 + # CONFIGURE SINGLE LAYOUT + p1000.configure_nozzle_layout( + style=SINGLE, start="H1", tip_racks=[tiprack_x_1, tiprack_x_2, tiprack_x_3] + ) + helpers.find_liquid_height_of_all_wells(protocol, p1000, wells) + tiprack_x_1.reset() + + sample_quant_csv = """ + sample_plate_1, Sample_well,DYE,DILUENT + sample_plate_1,A1,0,100 + sample_plate_1,B1,5,95 + sample_plate_1,C1,10,90 + sample_plate_1,D1,20,80 + sample_plate_1,E1,40,60 + sample_plate_1,F1,15,40 + sample_plate_1,G1,40,20 + sample_plate_1,H1,40,0 + sample_plate_1,A2,35,65 + sample_plate_1,B2,38,42 + sample_plate_1,C2,42,58 + sample_plate_1,D2,32,8 + sample_plate_1,E2,38,12 + sample_plate_1,F2,26,74 + sample_plate_1,G2,31,69 + sample_plate_1,H2,46,4 + sample_plate_1,A3,47,13 + sample_plate_1,B3,42,18 + sample_plate_1,C3,46,64 + sample_plate_1,D3,48,22 + sample_plate_1,E3,26,74 + sample_plate_1,F3,34,66 + sample_plate_1,G3,43,37 + sample_plate_1,H3,20,80 + sample_plate_1,A4,44,16 + sample_plate_1,B4,49,41 + sample_plate_1,C4,48,42 + sample_plate_1,D4,44,16 + sample_plate_1,E4,47,53 + sample_plate_1,F4,47,33 + sample_plate_1,G4,42,48 + sample_plate_1,H4,39,21 + sample_plate_1,A5,30,20 + sample_plate_1,B5,36,14 + sample_plate_1,C5,31,59 + sample_plate_1,D5,38,52 + sample_plate_1,E5,36,4 + sample_plate_1,F5,32,28 + sample_plate_1,G5,35,55 + sample_plate_1,H5,39,1 + sample_plate_1,A6,31,59 + sample_plate_1,B6,20,80 + sample_plate_1,C6,38,2 + sample_plate_1,D6,34,46 + sample_plate_1,E6,30,70 + sample_plate_1,F6,32,58 + sample_plate_1,G6,21,79 + sample_plate_1,H6,38,52 + sample_plate_1,A7,33,27 + sample_plate_1,B7,34,16 + sample_plate_1,C7,40,60 + sample_plate_1,D7,34,26 + sample_plate_1,E7,30,20 + sample_plate_1,F7,44,56 + sample_plate_1,G7,26,74 + sample_plate_1,H7,45,55 + sample_plate_1,A8,39,1 + sample_plate_1,B8,38,2 + sample_plate_1,C8,34,66 + sample_plate_1,D8,39,11 + sample_plate_1,E8,46,54 + sample_plate_1,F8,37,63 + sample_plate_1,G8,38,42 + sample_plate_1,H8,34,66 + sample_plate_1,A9,44,56 + sample_plate_1,B9,39,11 + sample_plate_1,C9,30,70 + sample_plate_1,D9,37,33 + sample_plate_1,E9,46,54 + sample_plate_1,F9,39,21 + sample_plate_1,G9,29,41 + sample_plate_1,H9,23,77 + sample_plate_1,A10,26,74 + sample_plate_1,B10,39,1 + sample_plate_1,C10,31,49 + sample_plate_1,D10,38,62 + sample_plate_1,E10,29,1 + sample_plate_1,F10,21,79 + sample_plate_1,G10,29,41 + sample_plate_1,H10,28,42 + sample_plate_1,A11,15,55 + sample_plate_1,B11,28,72 + sample_plate_1,C11,11,49 + sample_plate_1,D11,34,66 + sample_plate_1,E11,27,73 + sample_plate_1,F11,30,40 + sample_plate_1,G11,33,67 + sample_plate_1,H11,31,39 + sample_plate_1,A12,39,31 + sample_plate_1,B12,47,53 + sample_plate_1,C12,46,54 + sample_plate_1,D12,13,7 + sample_plate_1,E12,34,46 + sample_plate_1,F12,45,35 + sample_plate_1,G12,28,42 + sample_plate_1,H12,37,63 + """ + + data = [r.split(",") for r in sample_quant_csv.strip().splitlines() if r][1:] + for X in range(1): + protocol.comment("==============================================") + protocol.comment("Adding Dye Sample Plate 1") + protocol.comment("==============================================") + + current = 0 + + well = get_next_tip_by_row(current_rack, p1000) + p1000.pick_up_tip(well) + while current < len(data): + CurrentWell = str(data[current][1]) + DyeVol = float(data[current][2]) + if DyeVol != 0 and DyeVol < 100: + p1000.liquid_presence_detection = False + p1000.transfer( + DyeVol, + Dye_1.bottom(z=2), + sample_plate_1.wells_by_name()[CurrentWell].top(z=1), + new_tip="never", + ) + if DyeVol > 20: + wells.append(sample_plate_1.wells_by_name()[CurrentWell]) + current += 1 + p1000.blow_out() + p1000.touch_tip() + p1000.drop_tip() + p1000.liquid_presence_detection = True + + protocol.comment("==============================================") + protocol.comment("Adding Diluent Sample Plate 1") + protocol.comment("==============================================") + + current = 0 + while current < len(data): + CurrentWell = str(data[current][1]) + DilutionVol = float(data[current][2]) + if DilutionVol != 0 and DilutionVol < 100: + well = get_next_tip_by_row(current_rack, p1000) + p1000.pick_up_tip(well) + p1000.aspirate(DilutionVol, Diluent_1.bottom(z=2)) + p1000.dispense( + DilutionVol, sample_plate_1.wells_by_name()[CurrentWell].top(z=0.2) + ) + if DilutionVol > 20: + wells.append(sample_plate_1.wells_by_name()[CurrentWell]) + p1000.blow_out() + p1000.touch_tip() + p1000.drop_tip() + current += 1 + + protocol.comment("==============================================") + protocol.comment("Adding Dye Sample Plate 2") + protocol.comment("==============================================") + + current = 0 + well = get_next_tip_by_row(tiprack_x_2, p1000) + p1000.pick_up_tip(well) + while current < len(data): + CurrentWell = str(data[current][1]) + DyeVol = float(data[current][2]) + if DyeVol != 0 and DyeVol < 100: + p1000.transfer( + DyeVol, + Dye_2.bottom(z=2), + sample_plate_2.wells_by_name()[CurrentWell].top(z=1), + new_tip="never", + ) + if DyeVol > 20: + wells.append(sample_plate_2.wells_by_name()[CurrentWell]) + current += 1 + p1000.blow_out() + p1000.touch_tip() + p1000.drop_tip() + + protocol.comment("==============================================") + protocol.comment("Adding Diluent Sample Plate 2") + protocol.comment("==============================================") + + current = 0 + while current < len(data): + CurrentWell = str(data[current][1]) + DilutionVol = float(data[current][2]) + if DilutionVol != 0 and DilutionVol < 100: + well = get_next_tip_by_row(tiprack_x_2, p1000) + p1000.pick_up_tip(well) + p1000.aspirate(DilutionVol, Diluent_2.bottom(z=2)) + p1000.dispense( + DilutionVol, sample_plate_2.wells_by_name()[CurrentWell].top(z=0.2) + ) + if DilutionVol > 20: + wells.append(sample_plate_2.wells_by_name()[CurrentWell]) + p1000.blow_out() + p1000.touch_tip() + p1000.drop_tip() + current += 1 + + protocol.comment("==============================================") + protocol.comment("Adding Dye Sample Plate 3") + protocol.comment("==============================================") + + current = 0 + well = get_next_tip_by_row(tiprack_x_3, p1000) + p1000.pick_up_tip(well) + while current < len(data): + CurrentWell = str(data[current][1]) + DyeVol = float(data[current][2]) + if DyeVol != 0 and DyeVol < 100: + p1000.liquid_presence_detection = False + p1000.transfer( + DyeVol, + Dye_3.bottom(z=2), + sample_plate_3.wells_by_name()[CurrentWell].top(z=1), + blow_out=True, + blowout_location="destination well", + new_tip="never", + ) + if DyeVol > 20: + wells.append(sample_plate_3.wells_by_name()[CurrentWell]) + current += 1 + p1000.liquid_presence_detection = True + p1000.blow_out() + p1000.touch_tip() + p1000.drop_tip() + protocol.comment("==============================================") + protocol.comment("Adding Diluent Sample Plate 3") + protocol.comment("==============================================") + + current = 0 + # Probe heights + helpers.find_liquid_height_of_all_wells(protocol, p1000, wells) diff --git a/abr-testing/abr_testing/protocols/api 2.20/bms_pcr_protocol_220api.py b/abr-testing/abr_testing/protocols/active_protocols/2_BMS_PCR_Protocol.py similarity index 66% rename from abr-testing/abr_testing/protocols/api 2.20/bms_pcr_protocol_220api.py rename to abr-testing/abr_testing/protocols/active_protocols/2_BMS_PCR_Protocol.py index 873f7026d09..d044b5e8ed3 100644 --- a/abr-testing/abr_testing/protocols/api 2.20/bms_pcr_protocol_220api.py +++ b/abr-testing/abr_testing/protocols/active_protocols/2_BMS_PCR_Protocol.py @@ -5,10 +5,9 @@ ThermocyclerContext, TemperatureModuleContext, ) -from opentrons.protocol_api import SINGLE +from opentrons.protocol_api import SINGLE, Well from abr_testing.protocols import helpers -from opentrons.hardware_control.modules.types import ThermocyclerStep -from typing import List +from typing import List, Dict metadata = { @@ -20,32 +19,28 @@ def add_parameters(parameters: ParameterContext) -> None: """Parameters.""" - helpers.create_pipette_mount_parameter(parameters) + helpers.create_single_pipette_mount_parameter(parameters) helpers.create_disposable_lid_parameter(parameters) - parameters.add_csv_file( - display_name="Samples", - variable_name="samples_csv", - description="Asp/ disp volumes.", - ) + helpers.create_csv_parameter(parameters) def run(ctx: ProtocolContext) -> None: """Protocol.""" pipette_mount = ctx.params.pipette_mount # type: ignore[attr-defined] disposable_lid = ctx.params.disposable_lid # type: ignore[attr-defined] - parsed_csv = ctx.params.csv_data.parse_as_csv() # type: ignore[attr-defined] + parsed_csv = ctx.params.parameters_csv.parse_as_csv() # type: ignore[attr-defined] rxn_vol = 50 real_mode = True # DECK SETUP AND LABWARE tc_mod: ThermocyclerContext = ctx.load_module( - "thermocyclerModuleV2" + helpers.tc_str ) # type: ignore[assignment] tc_mod.open_lid() tc_mod.set_lid_temperature(105) temp_mod: TemperatureModuleContext = ctx.load_module( - "temperature module gen2", location="D3" + helpers.temp_str, location="D3" ) # type: ignore[assignment] reagent_rack = temp_mod.load_labware( "opentrons_24_aluminumblock_nest_1.5ml_snapcap" @@ -77,41 +72,38 @@ def run(ctx: ProtocolContext) -> None: ) p50.configure_nozzle_layout(style=SINGLE, start="A1", tip_racks=tiprack_50) ctx.load_trash_bin("A3") - mmx_liq = ctx.define_liquid( - name="Mastermix", description="Mastermix", display_color="#008000" - ) - water_liq = ctx.define_liquid( - name="Water", description="Water", display_color="#A52A2A" - ) - dna_liq = ctx.define_liquid(name="DNA", description="DNA", display_color="#A52A2A") - - # mapping temp_mod.set_temperature(4) - water = reagent_rack["B1"] - water.load_liquid(liquid=water_liq, volume=1500) - # - mmx_pic = reagent_rack.rows()[0] - for mmx_well in mmx_pic: - mmx_well.load_liquid(liquid=mmx_liq, volume=1500) - - dna_pic = source_plate.wells() - for dna_well in dna_pic: - dna_well.load_liquid(liquid=dna_liq, volume=50) - + # LOAD LIQUIDS + water: Well = reagent_rack["B1"] + mmx_pic: List[Well] = reagent_rack.rows()[0] + dna_pic: List[Well] = source_plate.wells() + liquid_vols_and_wells: Dict[str, List[Dict[str, Well | List[Well] | float]]] = { + "Water": [{"well": water, "volume": 1500.0}], + "Mastermix": [{"well": mmx_pic, "volume": 1500.0}], + "DNA": [{"well": dna_pic, "volume": 50.0}], + } + helpers.load_wells_with_custom_liquids(ctx, liquid_vols_and_wells) + wells_to_probe = [[water], mmx_pic, dna_pic] + wells_to_probe_flattened = [ + well for list_of_wells in wells_to_probe for well in list_of_wells + ] + helpers.find_liquid_height_of_all_wells(ctx, p50, wells_to_probe_flattened) # adding water ctx.comment("\n\n----------ADDING WATER----------\n") p50.pick_up_tip() # p50.aspirate(40, water) # prewet # p50.dispense(40, water) + parsed_csv = parsed_csv[1:] num_of_rows = len(parsed_csv) - for row in range(num_of_rows): - water_vol = row[1] + for row_index in range(num_of_rows): + row_values = parsed_csv[row_index] + water_vol = row_values[1] if water_vol.lower() == "x": continue - water_vol = int(row[1]) - dest_well = row[0] + water_vol = int(water_vol) + dest_well = row_values[0] if water_vol == 0: break @@ -119,13 +111,12 @@ def run(ctx: ProtocolContext) -> None: p50.aspirate(water_vol, water) p50.dispense(water_vol, dest_plate[dest_well], rate=0.5) p50.configure_for_volume(50) - # p50.blow_out() p50.drop_tip() # adding Mastermix ctx.comment("\n\n----------ADDING MASTERMIX----------\n") - for i, row in enumerate(csv_lines): + for i, row in enumerate(parsed_csv): p50.pick_up_tip() mmx_vol = row[3] if mmx_vol.lower() == "x": @@ -156,14 +147,12 @@ def run(ctx: ProtocolContext) -> None: p50.touch_tip() p50.configure_for_volume(50) p50.drop_tip() - if p50.has_tip: p50.drop_tip() # adding DNA ctx.comment("\n\n----------ADDING DNA----------\n") - for row in csv_lines: - + for row in parsed_csv: dna_vol = row[2] if dna_vol.lower() == "x": continue @@ -186,34 +175,34 @@ def run(ctx: ProtocolContext) -> None: ) p50.drop_tip() p50.configure_for_volume(50) + wells_to_probe_flattened.append(dest_plate[dest_well]) ctx.comment("\n\n-----------Running PCR------------\n") if real_mode: - - profile1: List[ThermocyclerStep] = [ - {"temperature": 95, "hold_time_minutes": 2}, - ] - profile2: List[ThermocyclerStep] = [ - {"temperature": 98, "hold_time_seconds": 10}, - {"temperature": 58, "hold_time_seconds": 10}, - {"temperature": 72, "hold_time_seconds": 30}, - ] - profile3: List[ThermocyclerStep] = [{"temperature": 72, "hold_time_minutes": 5}] if disposable_lid: lid_on_plate, unused_lids, used_lids = helpers.use_disposable_lid_with_tc( ctx, unused_lids, used_lids, dest_plate, tc_mod ) else: tc_mod.close_lid() - tc_mod.execute_profile(steps=profile1, repetitions=1, block_max_volume=50) - tc_mod.execute_profile(steps=profile2, repetitions=30, block_max_volume=50) - tc_mod.execute_profile(steps=profile3, repetitions=1, block_max_volume=50) + helpers.perform_pcr( + ctx, + tc_mod, + initial_denature_time_sec=120, + denaturation_time_sec=10, + anneal_time_sec=10, + extension_time_sec=30, + cycle_repetitions=30, + final_extension_time_min=5, + ) + tc_mod.set_block_temperature(4) - tc_mod.open_lid() - if disposable_lid: - if len(used_lids) <= 1: - ctx.move_labware(lid_on_plate, "C2", use_gripper=True) - else: - ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) + tc_mod.open_lid() + if disposable_lid: + if len(used_lids) <= 1: + ctx.move_labware(lid_on_plate, "C2", use_gripper=True) + else: + ctx.move_labware(lid_on_plate, used_lids[-2], use_gripper=True) + helpers.find_liquid_height_of_all_wells(ctx, p50, wells_to_probe_flattened) diff --git a/abr-testing/abr_testing/protocols/active_protocols/3_OT3 ABR Normalize with Tubes.py b/abr-testing/abr_testing/protocols/active_protocols/3_OT3 ABR Normalize with Tubes.py new file mode 100644 index 00000000000..e25e4a6d7c8 --- /dev/null +++ b/abr-testing/abr_testing/protocols/active_protocols/3_OT3 ABR Normalize with Tubes.py @@ -0,0 +1,344 @@ +"""FLEX Normalize with Tubes.""" +from opentrons.protocol_api import ProtocolContext, ParameterContext, Well +from abr_testing.protocols import helpers +from typing import List + +metadata = { + "protocolName": "Flex Normalize with Tubes", + "author": "Opentrons ", + "source": "Protocol Library", +} + +requirements = {"robotType": "Flex", "apiLevel": "2.20"} + +# SCRIPT SETTINGS +ABR_TEST = True +if ABR_TEST: + DRYRUN = True # True = skip incubation times, shorten mix, for testing purposes + TIP_TRASH = ( + False # True = Used tips go in Trash, False = Used tips go back into rack + ) +else: + DRYRUN = False # True = skip incubation times, shorten mix, for testing purposes + TIP_TRASH = True + + +def add_parameters(parameters: ParameterContext) -> None: + """Parameters.""" + helpers.create_csv_parameter(parameters) + helpers.create_dot_bottom_parameter(parameters) + helpers.create_two_pipette_mount_parameters(parameters) + + +def run(ctx: ProtocolContext) -> None: + """Protocol.""" + mount_pos_50ul = ctx.params.pipette_mount_1 # type: ignore[attr-defined] + mount_pos_1000ul = ctx.params.pipette_mount_2 # type: ignore[attr-defined] + dot_bottom = ctx.params.dot_bottom # type: ignore[attr-defined] + parsed_csv = ctx.params.parameters_csv.parse_as_csv() # type: ignore[attr-defined] + if DRYRUN: + ctx.comment("THIS IS A DRY RUN") + else: + ctx.comment("THIS IS A REACTION RUN") + + # labware + tiprack_50_1 = ctx.load_labware("opentrons_flex_96_tiprack_50ul", "1") + tiprack_200_1 = ctx.load_labware("opentrons_flex_96_tiprack_200ul", "4") + reagent_tube = ctx.load_labware( + "opentrons_10_tuberack_falcon_4x50ml_6x15ml_conical", "5", "Reagent Tube" + ) + sample_plate = ctx.load_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", "2", "Sample Plate" + ) + + # reagent + RSB = reagent_tube.wells()[0] + + # pipette + p1000 = ctx.load_instrument( + "flex_1channel_1000", mount_pos_1000ul, tip_racks=[tiprack_200_1] + ) + p50 = ctx.load_instrument( + "flex_1channel_50", mount_pos_50ul, tip_racks=[tiprack_50_1] + ) + + wells_with_liquids: List[Well] = [RSB] + helpers.load_wells_with_water(ctx, wells_with_liquids, [4000.0]) + helpers.find_liquid_height_of_all_wells(ctx, p50, wells_with_liquids) + MaxTubeVol = 200 + RSBVol = 0.0 + + data = parsed_csv + current = 1 + while current < len(data): + + CurrentWell = str(data[current][1]) + if float(data[current][2]) > 0: + InitialVol = float(data[current][2]) + else: + InitialVol = 0 + if float(data[current][3]) > 0: + InitialConc = float(data[current][3]) + else: + InitialConc = 0 + if float(data[current][4]) > 0: + TargetConc = float(data[current][4]) + else: + TargetConc = 0 + TotalDNA = float(InitialConc * InitialVol) + if TargetConc > 0: + TargetVol = float(TotalDNA / TargetConc) + else: + TargetVol = InitialVol + if TargetVol > InitialVol: + DilutionVol = float(TargetVol - InitialVol) + else: + DilutionVol = 0 + FinalVol = float(DilutionVol + InitialVol) + if TotalDNA > 0 and FinalVol > 0: + FinalConc = float(TotalDNA / FinalVol) + else: + FinalConc = 0 + + if DilutionVol <= 1: + ctx.comment("Sample " + CurrentWell + ": Conc. Too Low, Will Skip") + elif DilutionVol > MaxTubeVol - InitialVol: + DilutionVol = MaxTubeVol - InitialVol + ctx.comment( + "Sample " + + CurrentWell + + ": Conc. Too High, Will add, " + + str(DilutionVol) + + "ul, Max = " + + str(MaxTubeVol) + + "ul" + ) + RSBVol += MaxTubeVol - InitialVol + else: + if DilutionVol <= 20: + ctx.comment( + "Sample " + + CurrentWell + + ": Using p50, will add " + + str(round(DilutionVol, 1)) + ) + elif DilutionVol > 20: + ctx.comment( + "Sample " + + CurrentWell + + ": Using p1000, will add " + + str(round(DilutionVol, 1)) + ) + RSBVol += DilutionVol + current += 1 + + if RSBVol >= 14000: + ctx.pause("Caution, more than 15ml Required") + else: + ctx.comment("RSB Minimum: " + str(round(RSBVol / 1000, 1) + 1) + "ml") + + PiR2 = 176.71 + InitialRSBVol = RSBVol + RSBHeight = (InitialRSBVol / PiR2) + 17.5 + + ctx.pause("Proceed") + ctx.comment("==============================================") + ctx.comment("Normalizing Samples") + ctx.comment("==============================================") + + current = 1 + while current < len(data): + + CurrentWell = str(data[current][1]) + if float(data[current][2]) > 0: + InitialVol = float(data[current][2]) + else: + InitialVol = 0 + if float(data[current][3]) > 0: + InitialConc = float(data[current][3]) + else: + InitialConc = 0 + if float(data[current][4]) > 0: + TargetConc = float(data[current][4]) + else: + TargetConc = 0 + TotalDNA = float(InitialConc * InitialVol) + if TargetConc > 0: + TargetVol = float(TotalDNA / TargetConc) + else: + TargetVol = InitialVol + if TargetVol > InitialVol: + DilutionVol = float(TargetVol - InitialVol) + else: + DilutionVol = 0 + FinalVol = float(DilutionVol + InitialVol) + if TotalDNA > 0 and FinalVol > 0: + FinalConc = float(TotalDNA / FinalVol) + else: + FinalConc = 0 + + ctx.comment("Number " + str(data[current]) + ": Sample " + str(CurrentWell)) + # ctx.comment("Vol Height = "+str(round(RSBHeight,2))) + HeightDrop = DilutionVol / PiR2 + # ctx.comment("Vol Drop = "+str(round(HeightDrop,2))) + + if DilutionVol <= 0: + # If the No Volume + ctx.comment("Conc. Too Low, Skipping") + + elif DilutionVol >= MaxTubeVol - InitialVol: + # If the Required Dilution volume is >= Max Volume + DilutionVol = MaxTubeVol - InitialVol + ctx.comment( + "Conc. Too High, Will add, " + + str(DilutionVol) + + "ul, Max = " + + str(MaxTubeVol) + + "ul" + ) + p1000.pick_up_tip() + p1000.require_liquid_presence(RSB) + p1000.aspirate(DilutionVol, RSB.bottom(RSBHeight - (HeightDrop))) + RSBHeight -= HeightDrop + # ctx.comment("New Vol Height = "+str(round(RSBHeight,2))) + p1000.dispense(DilutionVol, sample_plate.wells_by_name()[CurrentWell]) + wells_with_liquids.append(sample_plate.wells_by_name()[CurrentWell]) + HighVolMix = 10 + for Mix in range(HighVolMix): + p1000.move_to(sample_plate.wells_by_name()[CurrentWell].center()) + p1000.aspirate(100) + p1000.move_to( + sample_plate.wells_by_name()[CurrentWell].bottom(0.5) + ) # original = () + p1000.aspirate(100) + p1000.dispense(100) + p1000.move_to(sample_plate.wells_by_name()[CurrentWell].center()) + p1000.dispense(100) + wells_with_liquids.append(sample_plate.wells_by_name()[CurrentWell]) + Mix += 1 + p1000.move_to(sample_plate.wells_by_name()[CurrentWell].top()) + ctx.delay(seconds=3) + p1000.blow_out() + p1000.drop_tip() if DRYRUN is False else p1000.return_tip() + + else: + if DilutionVol <= 20: + # If the Required Dilution volume is <= 20ul + ctx.comment("Using p50 to add " + str(round(DilutionVol, 1))) + p50.pick_up_tip() + if round(float(data[current][3]), 1) <= 20: + p50.require_liquid_presence(RSB) + p50.aspirate(DilutionVol, RSB.bottom(RSBHeight - (HeightDrop))) + RSBHeight -= HeightDrop + else: + p50.require_liquid_presence(RSB) + p50.aspirate(20, RSB.bottom(RSBHeight - (HeightDrop))) + RSBHeight -= HeightDrop + p50.dispense(DilutionVol, sample_plate.wells_by_name()[CurrentWell]) + wells_with_liquids.append(sample_plate.wells_by_name()[CurrentWell]) + p50.move_to( + sample_plate.wells_by_name()[CurrentWell].bottom(z=dot_bottom) + ) # original = () + # Mix volume <=20ul + if DilutionVol + InitialVol <= 20: + p50.mix(10, DilutionVol + InitialVol) + elif DilutionVol + InitialVol > 20: + p50.mix(10, 20) + p50.move_to(sample_plate.wells_by_name()[CurrentWell].top()) + ctx.delay(seconds=3) + p50.blow_out() + p50.drop_tip() if DRYRUN is False else p50.return_tip() + + elif DilutionVol > 20: + # If the required volume is >20 + ctx.comment("Using p1000 to add " + str(round(DilutionVol, 1))) + p1000.pick_up_tip() + p1000.require_liquid_presence(RSB) + p1000.aspirate(DilutionVol, RSB.bottom(RSBHeight - (HeightDrop))) + RSBHeight -= HeightDrop + if DilutionVol + InitialVol >= 120: + HighVolMix = 10 + for Mix in range(HighVolMix): + p1000.move_to( + sample_plate.wells_by_name()[CurrentWell].center() + ) + p1000.aspirate(100) + p1000.move_to( + sample_plate.wells_by_name()[CurrentWell].bottom( + z=dot_bottom + ) + ) # original = () + p1000.aspirate(DilutionVol + InitialVol - 100) + p1000.dispense(100) + p1000.move_to( + sample_plate.wells_by_name()[CurrentWell].center() + ) + p1000.dispense(DilutionVol + InitialVol - 100) + Mix += 1 + wells_with_liquids.append( + sample_plate.wells_by_name()[CurrentWell] + ) + else: + p1000.dispense( + DilutionVol, sample_plate.wells_by_name()[CurrentWell] + ) + p1000.move_to( + sample_plate.wells_by_name()[CurrentWell].bottom(z=dot_bottom) + ) # original = () + p1000.mix(10, DilutionVol + InitialVol) + p1000.move_to(sample_plate.wells_by_name()[CurrentWell].top()) + wells_with_liquids.append(sample_plate.wells_by_name()[CurrentWell]) + ctx.delay(seconds=3) + p1000.blow_out() + p1000.drop_tip() if DRYRUN is False else p1000.return_tip() + current += 1 + + ctx.comment("==============================================") + ctx.comment("Results") + ctx.comment("==============================================") + + current = 1 + while current < len(data): + + CurrentWell = str(data[current][1]) + if float(data[current][2]) > 0: + InitialVol = float(data[current][2]) + else: + InitialVol = 0 + if float(data[current][3]) > 0: + InitialConc = float(data[current][3]) + else: + InitialConc = 0 + if float(data[current][4]) > 0: + TargetConc = float(data[current][4]) + else: + TargetConc = 0 + TotalDNA = float(InitialConc * InitialVol) + if TargetConc > 0: + TargetVol = float(TotalDNA / TargetConc) + else: + TargetVol = InitialVol + if TargetVol > InitialVol: + DilutionVol = float(TargetVol - InitialVol) + else: + DilutionVol = 0 + if DilutionVol > MaxTubeVol - InitialVol: + DilutionVol = MaxTubeVol - InitialVol + FinalVol = float(DilutionVol + InitialVol) + if TotalDNA > 0 and FinalVol > 0: + FinalConc = float(TotalDNA / FinalVol) + else: + FinalConc = 0 + ctx.comment( + "Sample " + + CurrentWell + + ": " + + str(round(FinalVol, 1)) + + " at " + + str(round(FinalConc, 1)) + + "ng/ul" + ) + + current += 1 + print(wells_with_liquids) + helpers.find_liquid_height_of_all_wells(ctx, p50, wells_with_liquids) diff --git a/abr-testing/abr_testing/protocols/api 2.20/5_96ch complex protocol with single tip Pick Up.py b/abr-testing/abr_testing/protocols/active_protocols/5_96ch complex protocol with single tip Pick Up.py similarity index 92% rename from abr-testing/abr_testing/protocols/api 2.20/5_96ch complex protocol with single tip Pick Up.py rename to abr-testing/abr_testing/protocols/active_protocols/5_96ch complex protocol with single tip Pick Up.py index 502e89cf8a9..86801cfcc6e 100644 --- a/abr-testing/abr_testing/protocols/api 2.20/5_96ch complex protocol with single tip Pick Up.py +++ b/abr-testing/abr_testing/protocols/active_protocols/5_96ch complex protocol with single tip Pick Up.py @@ -14,7 +14,6 @@ ) from abr_testing.protocols import helpers from typing import List -from opentrons.hardware_control.modules.types import ThermocyclerStep metadata = { "protocolName": "96ch protocol with modules gripper moves and SINGLE tip pickup", @@ -68,9 +67,9 @@ def run(ctx: ProtocolContext) -> None: h_s.open_labware_latch() temperature_module_adapter = temperature_module.load_adapter( - helpers.temp_adapter_str + "opentrons_96_well_aluminum_block" ) - h_s_adapter = h_s.load_adapter(helpers.hs_adapter_str) + h_s_adapter = h_s.load_adapter("opentrons_96_pcr_adapter") adapters = [temperature_module_adapter, h_s_adapter] @@ -356,30 +355,17 @@ def test_thermocycler( thermocycler.set_lid_temperature(105) # Close lid thermocycler.close_lid() - # hold at 95° for 3 minutes - profile_TAG: List[ThermocyclerStep] = [ - {"temperature": 95, "hold_time_minutes": 3} - ] - thermocycler.execute_profile( - steps=profile_TAG, repetitions=1, block_max_volume=50 - ) - # 30x cycles of: 70° for 30s 72° for 30s 95° for 10s - profile_TAG2: List[ThermocyclerStep] = [ - {"temperature": 70, "hold_time_seconds": 30}, - {"temperature": 72, "hold_time_seconds": 30}, - {"temperature": 95, "hold_time_seconds": 10}, - ] - thermocycler.execute_profile( - steps=profile_TAG2, repetitions=30, block_max_volume=50 - ) - # hold at 72° for 5min - profile_TAG3: List[ThermocyclerStep] = [ - {"temperature": 72, "hold_time_minutes": 5} - ] - thermocycler.execute_profile( - steps=profile_TAG3, repetitions=1, block_max_volume=50 + helpers.perform_pcr( + ctx, + thermocycler, + initial_denature_time_sec=45, + denaturation_time_sec=30, + anneal_time_sec=30, + extension_time_sec=10, + cycle_repetitions=30, + final_extension_time_min=5, ) - # # Cool to 4° + # Cool to 4° thermocycler.set_block_temperature(4) thermocycler.set_lid_temperature(105) # Open lid diff --git a/abr-testing/abr_testing/protocols/api 2.20/7_HDQ_DNA_Bacteria_Flex.py b/abr-testing/abr_testing/protocols/active_protocols/7_HDQ_DNA_Bacteria_Flex.py similarity index 83% rename from abr-testing/abr_testing/protocols/api 2.20/7_HDQ_DNA_Bacteria_Flex.py rename to abr-testing/abr_testing/protocols/active_protocols/7_HDQ_DNA_Bacteria_Flex.py index 7475eb11a34..a11f4f94ed9 100644 --- a/abr-testing/abr_testing/protocols/api 2.20/7_HDQ_DNA_Bacteria_Flex.py +++ b/abr-testing/abr_testing/protocols/active_protocols/7_HDQ_DNA_Bacteria_Flex.py @@ -14,7 +14,7 @@ TemperatureModuleContext, MagneticBlockContext, ) -from typing import List, Union +from typing import List, Dict metadata = { "author": "Zach Galluzzo ", @@ -54,7 +54,7 @@ def add_parameters(parameters: ParameterContext) -> None: """Define Parameters.""" - helpers.create_pipette_mount_parameter(parameters) + helpers.create_single_pipette_mount_parameter(parameters) helpers.create_hs_speed_parameter(parameters) helpers.create_dot_bottom_parameter(parameters) @@ -97,25 +97,23 @@ def run(ctx: ProtocolContext) -> None: ctx.load_trash_bin("A3") h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] - h_s_adapter = h_s.load_adapter("opentrons_96_deep_well_adapter") - sample_plate = h_s_adapter.load_labware(deepwell_type, "Sample Plate") + sample_plate, h_s_adapter = helpers.load_hs_adapter_and_labware( + deepwell_type, h_s, "Sample Plate" + ) h_s.close_labware_latch() temp: TemperatureModuleContext = ctx.load_module( helpers.temp_str, "D3" ) # type: ignore[assignment] - temp_block = temp.load_adapter("opentrons_96_well_aluminum_block") - elutionplate = temp_block.load_labware( - "armadillo_96_wellplate_200ul_pcr_full_skirt", "Elution Plate" + elutionplate, temp_adapter = helpers.load_temp_adapter_and_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", temp, "Elution Plate" ) magnetic_block: MagneticBlockContext = ctx.load_module( helpers.mag_str, "C1" ) # type: ignore[assignment] - waste = ( - ctx.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") - .wells()[0] - .top() - ) - res1 = ctx.load_labware(res_type, "D2", "reagent reservoir 1") + waste_reservoir = ctx.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") + waste = waste_reservoir.wells()[0].top() + + res1 = ctx.load_labware(res_type, "D2", "Reagent Reservoir 1") num_cols = math.ceil(num_samples / 8) # Load tips and combine all similar boxes @@ -126,7 +124,9 @@ def run(ctx: ProtocolContext) -> None: tips_sn = tips1000.wells()[:num_samples] # load instruments - m1000 = ctx.load_instrument("flex_8channel_1000", mount) + m1000 = ctx.load_instrument( + "flex_8channel_1000", mount, tip_racks=[tips1000, tips1001, tips1002] + ) """ Here is where you can define the locations of your reagents. @@ -140,84 +140,25 @@ def run(ctx: ProtocolContext) -> None: samples_m = sample_plate.rows()[0][:num_cols] elution_samples_m = elutionplate.rows()[0][:num_cols] - colors = helpers.liquid_colors - - # Begin with assigning plate wells before reservoir wells - samps = ctx.define_liquid( - name="Samples", description="Samples", display_color="#00FF00" - ) - elution_samps = ctx.define_liquid( - name="Elution Buffer", description="Elution Buffer", display_color="#FFA500" - ) - - for well_s in sample_plate.wells()[:num_samples]: - well_s.load_liquid(liquid=samps, volume=sample_vol) - - for well_e in elutionplate.wells()[:num_samples]: - well_e.load_liquid(liquid=elution_samps, volume=elution_vol) - - # Start defining reservoir wells - locations: List[Union[List[Well], Well]] = [ - AL, - AL, - binding_buffer, - binding_buffer, - wash1, - wash2, - wash3, - ] - vols = [AL_vol, PK_vol, bead_vol, bind_vol, wash1_vol, wash2_vol, wash3_vol] - liquids = ["AL Lysis", "PK", "Beads", "Binding", "Wash 1", "Wash 2", "Wash 3"] - - delete = len(colors) - len(liquids) - - if delete >= 1: - for i in range(delete): - colors.pop(-1) - - def add_liquid( - liq_type: str, wells: Union[Well, List[Well]], color: str, vol: float - ) -> None: - """Assigns colored liquid to wells based on type and location.""" - total_samples = math.ceil(num_samples / 8) * 8 - - # Calculate extra sample volume based on liquid type - extra_samples = math.ceil( - 1500 - / (AL_vol if liq_type == "PK" else bind_vol if liq_type == "Beads" else vol) - ) - - # Define liquid - liquid = ctx.define_liquid( - name=liq_type, description=liq_type, display_color=color - ) - - # Assign liquid to each well - if isinstance(wells, list): - samples_per_well = [sample_max // len(wells)] * ( - total_samples // (sample_max // len(wells)) - ) - remainder = total_samples % (sample_max // len(wells)) - - if remainder: - samples_per_well.append(remainder) - - for sample_count, well in zip(samples_per_well, wells): - well.load_liquid( - liquid=liquid, volume=vol * (sample_count + extra_samples) - ) - else: - wells.load_liquid( - liquid=liquid, volume=vol * (total_samples + extra_samples) - ) - - # Apply function for each liquid configuration - for liq, well, color, vol in zip(liquids, locations, colors, vols): - add_liquid(liq, well, color, vol) + # Probe wells + liquid_vols_and_wells: Dict[str, List[Dict[str, Well | List[Well] | float]]] = { + "AL Lysis": [{"well": AL, "volume": AL_vol}], + "PK": [{"well": AL, "volume": PK_vol}], + "Beads": [{"well": binding_buffer, "volume": bead_vol}], + "Binding": [{"well": binding_buffer, "volume": bind_vol}], + "Wash 1": [{"well": wash1, "volume": wash1_vol}], + "Wash 2": [{"well": wash2, "volume": wash2_vol}], + "Wash 3": [{"well": wash3, "volume": wash3_vol}], + "Samples": [{"well": sample_plate.wells()[:num_samples], "volume": sample_vol}], + "Elution Buffer": [ + {"well": elutionplate.wells()[:num_samples], "volume": elution_vol} + ], + } m1000.flow_rate.aspirate = 300 m1000.flow_rate.dispense = 300 m1000.flow_rate.blow_out = 300 + helpers.find_liquid_height_of_loaded_liquids(ctx, liquid_vols_and_wells, m1000) def tiptrack(tipbox: List[Well]) -> None: """Track Tips.""" @@ -444,7 +385,7 @@ def bind(vol: float) -> None: helpers.set_hs_speed(ctx, h_s, speed_val, bind_time, True) # Transfer from H-S plate to Magdeck plate - helpers.move_labware_from_hs_to_mag_block( + helpers.move_labware_from_hs_to_destination( ctx, sample_plate, h_s, magnetic_block ) for bindi in np.arange( @@ -484,7 +425,7 @@ def wash(vol: float, source: List[Well]) -> None: helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, elute_wash_time, True) - helpers.move_labware_from_hs_to_mag_block( + helpers.move_labware_from_hs_to_destination( ctx, sample_plate, h_s, magnetic_block ) @@ -519,7 +460,7 @@ def elute(vol: float) -> None: helpers.set_hs_speed(ctx, h_s, speed_val, elute_wash_time, True) # Transfer back to magnet - helpers.move_labware_from_hs_to_mag_block( + helpers.move_labware_from_hs_to_destination( ctx, sample_plate, h_s, magnetic_block ) @@ -559,3 +500,11 @@ def elute(vol: float) -> None: msg="There are " + str(beaddry) + " minutes left in the drying step.", ) elute(elution_vol) + + # Probe wells + end_wells_with_liquid = [ + waste_reservoir.wells()[0], + res1.wells()[0], + elutionplate.wells()[0], + ] + helpers.find_liquid_height_of_all_wells(ctx, m1000, end_wells_with_liquid) diff --git a/abr-testing/abr_testing/protocols/active_protocols/8_Illumina and Plate Reader.py b/abr-testing/abr_testing/protocols/active_protocols/8_Illumina and Plate Reader.py new file mode 100644 index 00000000000..634cac538a0 --- /dev/null +++ b/abr-testing/abr_testing/protocols/active_protocols/8_Illumina and Plate Reader.py @@ -0,0 +1,949 @@ +"""Illumina DNA Prep and Plate Reader Test.""" +from opentrons.protocol_api import ParameterContext, ProtocolContext, Labware +from abr_testing.protocols import helpers +from opentrons.protocol_api.module_contexts import ( + AbsorbanceReaderContext, + ThermocyclerContext, + HeaterShakerContext, + TemperatureModuleContext, + MagneticBlockContext, +) +from datetime import datetime +from opentrons.hardware_control.modules.types import ThermocyclerStep +from typing import List +from opentrons import types + +metadata = { + "protocolName": "Illumina DNA Prep and Plate Reader Test", + "author": "Platform Expansion", +} + + +requirements = { + "robotType": "Flex", + "apiLevel": "2.21", +} + +HELLMA_PLATE_SLOT = "D4" +PLATE_READER_SLOT = "C3" + +# SCRIPT SETTINGS +DRYRUN = False # True = skip incubation times, shorten mix, for testing purposes +USE_GRIPPER = True # True = Uses Gripper, False = Manual Move +TIP_TRASH = False # True = Used tips go in Trash, False = Used tips go back into rack +HYBRID_PAUSE = True # True = sets a pause on the Hybridization + +# PROTOCOL SETTINGS +COLUMNS = 3 # 1-3 +HYBRIDDECK = True +HYBRIDTIME = 1.6 # Hours + +# PROTOCOL BLOCKS +STEP_VOLPOOL = 0 +STEP_HYB = 0 +STEP_CAPTURE = 1 +STEP_WASH = 1 +STEP_PCR = 1 +STEP_PCRDECK = 1 +STEP_CLEANUP = 1 + +p200_tips = 0 +p50_tips = 0 + + +RUN = 1 + + +def add_parameters(parameters: ParameterContext) -> None: + """Add Parameters.""" + helpers.create_hs_speed_parameter(parameters) + helpers.create_dot_bottom_parameter(parameters) + parameters.add_str( + variable_name="plate_orientation", + display_name="Hellma Plate Orientation", + default="0_deg", + choices=[ + {"display_name": "0 degree Rotation", "value": "0_deg"}, + {"display_name": "180 degree Rotation", "value": "180_deg"}, + ], + ) + + +def plate_reader_actions( + protocol: ProtocolContext, + plate_reader: AbsorbanceReaderContext, + hellma_plate: Labware, +) -> None: + """Plate reader single and multi wavelength readings.""" + wavelengths = [450, 650] + # Single Wavelength Readings + for wavelength in wavelengths: + plate_reader.initialize("single", [wavelength], reference_wavelength=wavelength) + plate_reader.open_lid() + protocol.move_labware(hellma_plate, plate_reader, use_gripper=True) + plate_reader.close_lid() + result = plate_reader.read(str(datetime.now())) + msg = f"result: {result}" + protocol.comment(msg=msg) + plate_reader.open_lid() + protocol.move_labware(hellma_plate, HELLMA_PLATE_SLOT, use_gripper=True) + plate_reader.close_lid() + # Multi Wavelength + plate_reader.initialize("multi", [450, 650]) + plate_reader.open_lid() + protocol.move_labware(hellma_plate, plate_reader, use_gripper=True) + plate_reader.close_lid() + result = plate_reader.read(str(datetime.now())) + msg = f"result: {result}" + protocol.comment(msg=msg) + plate_reader.open_lid() + protocol.move_labware(hellma_plate, HELLMA_PLATE_SLOT, use_gripper=True) + plate_reader.close_lid() + + +def run(protocol: ProtocolContext) -> None: + """Protocol.""" + # LOAD PARAMETERS + heater_shaker_speed = protocol.params.heater_shaker_speed # type: ignore[attr-defined] + dot_bottom = protocol.params.dot_bottom # type: ignore[attr-defined] + global p200_tips + global p50_tips + # WASTE BIN + protocol.load_waste_chute() + # TIP RACKS + tiprack_200_1 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "B2") + tiprack_200_2 = protocol.load_labware("opentrons_flex_96_tiprack_200ul", "C2") + tiprack_50_1 = protocol.load_labware("opentrons_flex_96_tiprack_50ul", "A2") + tiprack_50_2 = protocol.load_labware("opentrons_flex_96_tiprack_50ul", "A3") + # MODULES + LABWARE + # Reservoir + reservoir = protocol.load_labware("nest_96_wellplate_2ml_deep", "D2") + # Heatershaker + heatershaker: HeaterShakerContext = protocol.load_module( + helpers.hs_str, "D1" + ) # type: ignore[assignment] + sample_plate_2 = heatershaker.load_labware( + "thermoscientificnunc_96_wellplate_1300ul" + ) + # Magnetic Block + mag_block: MagneticBlockContext = protocol.load_module( + helpers.mag_str, "C1" + ) # type: ignore[assignment] + thermocycler: ThermocyclerContext = protocol.load_module( + helpers.tc_str + ) # type: ignore[assignment] + sample_plate_1 = thermocycler.load_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt" + ) + # Temperature Module + temp_block: TemperatureModuleContext = protocol.load_module( + helpers.temp_str, "B3" + ) # type: ignore[assignment] + reagent_plate, temp_adapter = helpers.load_temp_adapter_and_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", temp_block, "Reagent Plate" + ) + # Plate Reader + plate_reader: AbsorbanceReaderContext = protocol.load_module( + helpers.abs_mod_str, PLATE_READER_SLOT + ) # type: ignore[assignment] + hellma_plate = protocol.load_labware("hellma_reference_plate", HELLMA_PLATE_SLOT) + # PIPETTES + p1000 = protocol.load_instrument( + "flex_8channel_1000", + "left", + tip_racks=[tiprack_200_1, tiprack_200_2], + ) + p50 = protocol.load_instrument( + "flex_8channel_50", "right", tip_racks=[tiprack_50_1, tiprack_50_2] + ) + + plate_reader_actions(protocol, plate_reader, hellma_plate) + # reagent + AMPure = reservoir["A1"] + SMB = reservoir["A2"] + + EtOH = reservoir["A4"] + RSB = reservoir["A5"] + Liquid_trash_well_1 = reservoir["A9"] + Liquid_trash_well_2 = reservoir["A10"] + Liquid_trash_well_3 = reservoir["A11"] + Liquid_trash_well_4 = reservoir["A12"] + + # Will Be distributed during the protocol + EEW_1 = sample_plate_2.wells_by_name()["A10"] + EEW_2 = sample_plate_2.wells_by_name()["A11"] + EEW_3 = sample_plate_2.wells_by_name()["A12"] + + NHB2 = reagent_plate.wells_by_name()["A1"] + Panel = reagent_plate.wells_by_name()["A2"] + EHB2 = reagent_plate.wells_by_name()["A3"] + Elute = reagent_plate.wells_by_name()["A4"] + ET2 = reagent_plate.wells_by_name()["A5"] + PPC = reagent_plate.wells_by_name()["A6"] + EPM = reagent_plate.wells_by_name()["A7"] + + # tip and sample tracking + if COLUMNS == 1: + column_1_list = ["A1"] # Plate 1 + column_2_list = ["A1"] # Plate 2 + column_3_list = ["A4"] # Plate 2 + column_4_list = ["A4"] # Plate 1 + column_5_list = ["A7"] # Plate 2 + column_6_list = ["A7"] # Plate 1 + WASHES = [EEW_1] + if COLUMNS == 2: + column_1_list = ["A1", "A2"] # Plate 1 + column_2_list = ["A1", "A2"] # Plate 2 + column_3_list = ["A4", "A5"] # Plate 2 + column_4_list = ["A4", "A5"] # Plate 1 + column_5_list = ["A7", "A8"] # Plate 2 + column_6_list = ["A7", "A8"] # Plate 1 + WASHES = [EEW_1, EEW_2] + if COLUMNS == 3: + column_1_list = ["A1", "A2", "A3"] # Plate 1 + column_2_list = ["A1", "A2", "A3"] # Plate 2 + column_3_list = ["A4", "A5", "A6"] # Plate 2 + column_4_list = ["A4", "A5", "A6"] # Plate 1 + column_5_list = ["A7", "A8", "A9"] # Plate 2 + column_6_list = ["A7", "A8", "A9"] # Plate 1 + WASHES = [EEW_1, EEW_2, EEW_3] + + def tipcheck() -> None: + """Check tips.""" + if p200_tips >= 2 * 12: + p1000.reset_tipracks() + p200_tips == 0 + if p50_tips >= 2 * 12: + p50.reset_tipracks() + p50_tips == 0 + + # commands + for loop in range(RUN): + thermocycler.open_lid() + heatershaker.open_labware_latch() + if DRYRUN is False: + if STEP_HYB == 1: + protocol.comment("SETTING THERMO and TEMP BLOCK Temperature") + thermocycler.set_block_temperature(4) + thermocycler.set_lid_temperature(100) + temp_block.set_temperature(4) + else: + protocol.comment("SETTING THERMO and TEMP BLOCK Temperature") + thermocycler.set_block_temperature(58) + thermocycler.set_lid_temperature(58) + heatershaker.set_and_wait_for_temperature(58) + protocol.pause("Ready") + heatershaker.close_labware_latch() + Liquid_trash = Liquid_trash_well_1 + + # Sample Plate contains 30ul of DNA + + if STEP_VOLPOOL == 1: + protocol.comment("==============================================") + protocol.comment("--> Quick Vol Pool") + protocol.comment("==============================================") + + if STEP_HYB == 1: + protocol.comment("==============================================") + protocol.comment("--> HYB") + protocol.comment("==============================================") + + protocol.comment("--> Adding NHB2") + NHB2Vol = 50 + for loop, X in enumerate(column_1_list): + p50.pick_up_tip() + p50.aspirate(NHB2Vol, NHB2.bottom(z=dot_bottom)) # original = () + p50.dispense( + NHB2Vol, sample_plate_1[X].bottom(z=dot_bottom) + ) # original = () + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + protocol.comment("--> Adding Panel") + PanelVol = 10 + for loop, X in enumerate(column_1_list): + p50.pick_up_tip() + p50.aspirate(PanelVol, Panel.bottom(z=dot_bottom)) # original = () + p50.dispense( + PanelVol, sample_plate_1[X].bottom(z=dot_bottom) + ) # original = () + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + protocol.comment("--> Adding EHB2") + EHB2Vol = 10 + EHB2MixRep = 10 if DRYRUN is False else 1 + EHB2MixVol = 90 + for loop, X in enumerate(column_1_list): + p1000.pick_up_tip() + p1000.aspirate(EHB2Vol, EHB2.bottom(z=dot_bottom)) # original = () + p1000.dispense( + EHB2Vol, sample_plate_1[X].bottom(z=dot_bottom) + ) # original = () + p1000.move_to(sample_plate_1[X].bottom(z=dot_bottom)) # original = () + p1000.mix(EHB2MixRep, EHB2MixVol) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p50_tips += 1 + tipcheck() + + if HYBRIDDECK: + protocol.comment("Hybridize on Deck") + thermocycler.close_lid() + if DRYRUN is False: + profile_TAGSTOP: List[ThermocyclerStep] = [ + {"temperature": 98, "hold_time_minutes": 5}, + {"temperature": 97, "hold_time_minutes": 1}, + {"temperature": 95, "hold_time_minutes": 1}, + {"temperature": 93, "hold_time_minutes": 1}, + {"temperature": 91, "hold_time_minutes": 1}, + {"temperature": 89, "hold_time_minutes": 1}, + {"temperature": 87, "hold_time_minutes": 1}, + {"temperature": 85, "hold_time_minutes": 1}, + {"temperature": 83, "hold_time_minutes": 1}, + {"temperature": 81, "hold_time_minutes": 1}, + {"temperature": 79, "hold_time_minutes": 1}, + {"temperature": 77, "hold_time_minutes": 1}, + {"temperature": 75, "hold_time_minutes": 1}, + {"temperature": 73, "hold_time_minutes": 1}, + {"temperature": 71, "hold_time_minutes": 1}, + {"temperature": 69, "hold_time_minutes": 1}, + {"temperature": 67, "hold_time_minutes": 1}, + {"temperature": 65, "hold_time_minutes": 1}, + {"temperature": 63, "hold_time_minutes": 1}, + {"temperature": 62, "hold_time_minutes": HYBRIDTIME * 60}, + ] + thermocycler.execute_profile( + steps=profile_TAGSTOP, repetitions=1, block_max_volume=100 + ) + thermocycler.set_block_temperature(62) + if HYBRID_PAUSE: + protocol.comment("HYBRIDIZATION PAUSED") + thermocycler.set_block_temperature(10) + thermocycler.open_lid() + else: + protocol.comment("Hybridize off Deck") + + if STEP_CAPTURE == 1: + protocol.comment("==============================================") + protocol.comment("--> Capture") + protocol.comment("==============================================") + # Standard Setup + + if DRYRUN is False: + protocol.comment("SETTING THERMO and TEMP BLOCK Temperature") + thermocycler.set_block_temperature(58) + thermocycler.set_lid_temperature(58) + + if DRYRUN is False: + heatershaker.set_and_wait_for_temperature(58) + + protocol.comment("--> Transfer Hybridization") + TransferSup = 100 + for loop, X in enumerate(column_1_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_1[X].bottom(z=0.5)) + p1000.aspirate(TransferSup + 1, rate=0.25) + p1000.dispense( + TransferSup + 1, sample_plate_2[column_2_list[loop]].bottom(z=1) + ) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + thermocycler.close_lid() + + protocol.comment("--> ADDING SMB") + SMBVol = 250 + SMBMixRPM = heater_shaker_speed + SMBMixRep = 5 * 60 if DRYRUN is False else 0.1 * 60 + SMBPremix = 3 if DRYRUN is False else 1 + # ============================== + for loop, X in enumerate(column_2_list): + p1000.pick_up_tip() + p1000.mix(SMBPremix, 200, SMB.bottom(z=1)) + p1000.aspirate(SMBVol / 2, SMB.bottom(z=1), rate=0.25) + p1000.dispense(SMBVol / 2, sample_plate_2[X].top(z=-7), rate=0.25) + p1000.aspirate(SMBVol / 2, SMB.bottom(z=1), rate=0.25) + p1000.dispense(SMBVol / 2, sample_plate_2[X].bottom(z=1), rate=0.25) + p1000.default_speed = 5 + p1000.move_to(sample_plate_2[X].bottom(z=5)) + for Mix in range(2): + p1000.aspirate(100, rate=0.5) + p1000.move_to(sample_plate_2[X].bottom(z=1)) + p1000.aspirate(80, rate=0.5) + p1000.dispense(80, rate=0.5) + p1000.move_to(sample_plate_2[X].bottom(z=5)) + p1000.dispense(100, rate=0.5) + Mix += 1 + p1000.blow_out(sample_plate_2[X].top(z=-7)) + p1000.default_speed = 400 + p1000.move_to(sample_plate_2[X].top(z=5)) + p1000.move_to(sample_plate_2[X].top(z=0)) + p1000.move_to(sample_plate_2[X].top(z=5)) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + # ============================== + heatershaker.set_and_wait_for_shake_speed(rpm=SMBMixRPM) + protocol.delay(SMBMixRep) + heatershaker.deactivate_shaker() + + # ============================================================================================ + # GRIPPER MOVE sample_plate_2 FROM heatershaker TO MAGPLATE + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate_2, heatershaker, mag_block + ) + thermocycler.open_lid() + + if DRYRUN is False: + protocol.delay(minutes=2) + + protocol.comment("==============================================") + protocol.comment("--> WASH") + protocol.comment("==============================================") + # Setting Labware to Resume at Cleanup 1 + + protocol.comment("--> Remove SUPERNATANT") + for loop, X in enumerate(column_2_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_2[X].bottom(4)) + p1000.aspirate(200, rate=0.25) + p1000.dispense(200, Liquid_trash.top(z=-7)) + p1000.move_to(sample_plate_2[X].bottom(0.5)) + p1000.aspirate(200, rate=0.25) + p1000.dispense(200, Liquid_trash.top(z=-7)) + p1000.move_to(Liquid_trash.top(z=-7)) + protocol.delay(minutes=0.1) + p1000.blow_out(Liquid_trash.top(z=-7)) + p1000.aspirate(20) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + Liquid_trash = Liquid_trash_well_2 + + # ============================================================================================ + # GRIPPER MOVE sample_plate_2 FROM MAGPLATE TO heatershaker + helpers.move_labware_to_hs( + protocol, sample_plate_2, heatershaker, heatershaker + ) + # ============================================================================================ + + protocol.comment("--> Repeating 3 washes") + washreps = 3 + washcount = 0 + for wash in range(washreps): + + protocol.comment("--> Adding EEW") + EEWVol = 200 + for loop, X in enumerate(column_2_list): + p1000.pick_up_tip() + p1000.aspirate( + EEWVol, WASHES[loop].bottom(z=dot_bottom) + ) # original = () + p1000.dispense( + EEWVol, sample_plate_2[X].bottom(z=dot_bottom) + ) # original = () + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + heatershaker.close_labware_latch() + heatershaker.set_and_wait_for_shake_speed( + rpm=(heater_shaker_speed * 0.9) + ) + if DRYRUN is False: + protocol.delay(seconds=4 * 60) + heatershaker.deactivate_shaker() + heatershaker.open_labware_latch() + + if DRYRUN is False: + protocol.delay(seconds=5 * 60) + + # ============================================================================================ + # GRIPPER MOVE sample_plate_2 FROM heatershaker TO MAGPLATE + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate_2, heatershaker, mag_block + ) + + if DRYRUN is False: + protocol.delay(seconds=1 * 60) + + if washcount > 2: + Liquid_trash = Liquid_trash_well_3 + + protocol.comment("--> Removing Supernatant") + RemoveSup = 200 + for loop, X in enumerate(column_2_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_2[X].bottom(z=3.5)) + p1000.aspirate(RemoveSup - 100, rate=0.25) + protocol.delay(minutes=0.1) + p1000.move_to(sample_plate_2[X].bottom(z=0.5)) + p1000.aspirate(100, rate=0.25) + p1000.move_to(sample_plate_2[X].top(z=0.5)) + p1000.dispense(200, Liquid_trash.top(z=-7)) + protocol.delay(minutes=0.1) + p1000.blow_out(Liquid_trash.top(z=-7)) + p1000.aspirate(20) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + # ============================================================================================ + # GRIPPER MOVE sample_plate_2 FROM MAGPLATE TO heatershaker + helpers.move_labware_to_hs( + protocol, sample_plate_2, heatershaker, heatershaker + ) + washcount += 1 + + protocol.comment("--> Adding EEW") + EEWVol = 200 + for loop, X in enumerate(column_2_list): + p1000.pick_up_tip() + p1000.aspirate( + EEWVol, WASHES[loop].bottom(z=dot_bottom) + ) # original = () + p1000.dispense( + EEWVol, sample_plate_2[X].bottom(z=dot_bottom) + ) # original = () + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + heatershaker.set_and_wait_for_shake_speed(rpm=(heater_shaker_speed * 0.9)) + if DRYRUN is False: + protocol.delay(seconds=4 * 60) + heatershaker.deactivate_shaker() + + if DRYRUN is False: + protocol.delay(seconds=1 * 60) + + protocol.comment("--> Transfer Hybridization") + TransferSup = 200 + for loop, X in enumerate(column_2_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_2[X].bottom(z=0.5)) + p1000.aspirate(TransferSup, rate=0.25) + p1000.dispense( + TransferSup, sample_plate_2[column_3_list[loop]].bottom(z=1) + ) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + if DRYRUN is False: + protocol.delay(seconds=5 * 60) + + # ============================================================================================ + # GRIPPER MOVE sample_plate_2 FROM heatershaker TO MAGPLATE + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate_2, heatershaker, mag_block + ) + + if DRYRUN is False: + protocol.delay(seconds=1 * 60) + + protocol.comment("--> Removing Supernatant") + RemoveSup = 200 + for loop, X in enumerate(column_3_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_2[X].bottom(z=3.5)) + p1000.aspirate(RemoveSup - 100, rate=0.25) + protocol.delay(minutes=0.1) + p1000.move_to(sample_plate_2[X].bottom(z=0.5)) + p1000.aspirate(100, rate=0.25) + p1000.move_to(sample_plate_2[X].top(z=0.5)) + p1000.dispense(200, Liquid_trash.top(z=-7)) + protocol.delay(minutes=0.1) + p1000.blow_out(Liquid_trash.top(z=-7)) + p1000.aspirate(20) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + protocol.comment("--> Removing Residual") + for loop, X in enumerate(column_3_list): + p50.pick_up_tip() + p50.move_to(sample_plate_2[X].bottom(z=dot_bottom)) # original = z=0 + p50.aspirate(50, rate=0.25) + p50.default_speed = 200 + p50.dispense(50, Liquid_trash.top(z=-7)) + protocol.delay(minutes=0.1) + p50.blow_out() + p50.default_speed = 400 + p50.move_to(Liquid_trash.top(z=-7)) + p50.move_to(Liquid_trash.top(z=0)) + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + protocol.comment("==============================================") + protocol.comment("--> ELUTE") + protocol.comment("==============================================") + + protocol.comment("--> Adding Elute") + EluteVol = 23 + for loop, X in enumerate(column_3_list): + p50.pick_up_tip() + p50.aspirate(EluteVol, Elute.bottom(z=dot_bottom)) # original = () + p50.dispense( + EluteVol, sample_plate_2[X].bottom(z=dot_bottom) + ) # original = () + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + # ============================================================================================ + # GRIPPER MOVE sample_plate_2 FROM MAGPLATE TO heatershaker + helpers.move_labware_to_hs( + protocol, sample_plate_2, heatershaker, heatershaker + ) + # ============================================================================================ + + heatershaker.close_labware_latch() + heatershaker.set_and_wait_for_shake_speed(rpm=(heater_shaker_speed * 0.9)) + if DRYRUN is False: + protocol.delay(seconds=2 * 60) + heatershaker.deactivate_shaker() + heatershaker.open_labware_latch() + + if DRYRUN is False: + protocol.delay(minutes=2) + + # ============================================================================================ + # GRIPPER MOVE sample_plate_2 FROM heatershaker TO MAGPLATE + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate_2, heatershaker, mag_block + ) + protocol.comment("--> Transfer Elution") + TransferSup = 21 + for loop, X in enumerate(column_3_list): + p50.pick_up_tip() + p50.move_to(sample_plate_2[X].bottom(z=0.5)) + p50.aspirate(TransferSup + 1, rate=0.25) + p50.dispense( + TransferSup + 1, sample_plate_1[column_4_list[loop]].bottom(z=1) + ) + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + protocol.comment("--> Adding ET2") + ET2Vol = 4 + ET2MixRep = 10 if DRYRUN is False else 1 + ET2MixVol = 20 + for loop, X in enumerate(column_4_list): + p50.pick_up_tip() + p50.aspirate(ET2Vol, ET2.bottom(z=dot_bottom)) # original = () + p50.dispense( + ET2Vol, sample_plate_1[X].bottom(z=dot_bottom) + ) # original = () + p50.move_to(sample_plate_1[X].bottom(z=dot_bottom)) # original = () + p50.mix(ET2MixRep, ET2MixVol) + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + if STEP_PCR == 1: + protocol.comment("==============================================") + protocol.comment("--> AMPLIFICATION") + protocol.comment("==============================================") + + protocol.comment("--> Adding PPC") + PPCVol = 5 + for loop, X in enumerate(column_4_list): + p50.pick_up_tip() + p50.aspirate(PPCVol, PPC.bottom(z=dot_bottom)) # original = () + p50.dispense( + PPCVol, sample_plate_1[X].bottom(z=dot_bottom) + ) # original = () + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + protocol.comment("--> Adding EPM") + EPMVol = 20 + EPMMixRep = 10 if DRYRUN is False else 1 + EPMMixVol = 45 + for loop, X in enumerate(column_4_list): + p50.pick_up_tip() + p50.aspirate(EPMVol, EPM.bottom(z=dot_bottom)) # original = () + p50.dispense( + EPMVol, sample_plate_1[X].bottom(z=dot_bottom) + ) # original = () + p50.move_to(sample_plate_1[X].bottom(z=dot_bottom)) # original = () + p50.mix(EPMMixRep, EPMMixVol) + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + if DRYRUN is False: + heatershaker.deactivate_heater() + + if STEP_PCRDECK == 1: + if DRYRUN is False: + if DRYRUN is False: + thermocycler.close_lid() + helpers.perform_pcr( + protocol, + thermocycler, + initial_denature_time_sec=45, + denaturation_time_sec=30, + anneal_time_sec=30, + extension_time_sec=30, + cycle_repetitions=12, + final_extension_time_min=1, + ) + thermocycler.set_block_temperature(10) + + thermocycler.open_lid() + + if STEP_CLEANUP == 1: + protocol.comment("==============================================") + protocol.comment("--> Cleanup") + protocol.comment("==============================================") + + # GRIPPER MOVE sample_plate_2 FROM MAGPLATE TO heatershaker + helpers.move_labware_to_hs( + protocol, sample_plate_2, heatershaker, heatershaker + ) + + protocol.comment("--> Transfer Elution") + TransferSup = 45 + for loop, X in enumerate(column_4_list): + p50.pick_up_tip() + p50.move_to(sample_plate_1[X].bottom(z=0.5)) + p50.aspirate(TransferSup + 1, rate=0.25) + p50.dispense( + TransferSup + 1, sample_plate_2[column_5_list[loop]].bottom(z=1) + ) + p50.return_tip() if TIP_TRASH is False else p50.drop_tip() + p50_tips += 1 + tipcheck() + + Liquid_trash = Liquid_trash_well_4 + + protocol.comment("--> ADDING AMPure (0.8x)") + AMPureVol = 40.5 + AMPureMixRep = 5 * 60 if DRYRUN is False else 0.1 * 60 + AMPurePremix = 3 if DRYRUN is False else 1 + # ========NEW SINGLE TIP DISPENSE=========== + for loop, X in enumerate(column_5_list): + p1000.pick_up_tip() + p1000.mix(AMPurePremix, AMPureVol + 10, AMPure.bottom(z=1)) + p1000.aspirate(AMPureVol, AMPure.bottom(z=1), rate=0.25) + p1000.dispense(AMPureVol, sample_plate_2[X].bottom(z=1), rate=0.25) + p1000.default_speed = 5 + p1000.move_to(sample_plate_2[X].bottom(z=5)) + for Mix in range(2): + p1000.aspirate(60, rate=0.5) + p1000.move_to(sample_plate_2[X].bottom(z=1)) + p1000.aspirate(60, rate=0.5) + p1000.dispense(60, rate=0.5) + p1000.move_to(sample_plate_2[X].bottom(z=5)) + p1000.dispense(30, rate=0.5) + Mix += 1 + p1000.blow_out(sample_plate_2[X].top(z=2)) + p1000.default_speed = 400 + p1000.move_to(sample_plate_2[X].top(z=5)) + p1000.move_to(sample_plate_2[X].top(z=0)) + p1000.move_to(sample_plate_2[X].top(z=5)) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + # ========NEW HS MIX========================= + heatershaker.set_and_wait_for_shake_speed(rpm=(heater_shaker_speed * 0.9)) + protocol.delay(AMPureMixRep) + heatershaker.deactivate_shaker() + + # GRIPPER MOVE PLATE FROM HEATER SHAKER TO MAG PLATE + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate_2, heatershaker, mag_block + ) + + if DRYRUN is False: + protocol.delay(minutes=4) + + protocol.comment("--> Removing Supernatant") + RemoveSup = 200 + for loop, X in enumerate(column_5_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_2[X].bottom(z=3.5)) + p1000.aspirate(RemoveSup - 100, rate=0.25) + protocol.delay(minutes=0.1) + p1000.move_to(sample_plate_2[X].bottom(z=0.5)) + p1000.aspirate(100, rate=0.25) + p1000.default_speed = 5 + p1000.move_to(sample_plate_2[X].top(z=2)) + p1000.default_speed = 200 + p1000.dispense(200, Liquid_trash.top(z=-7)) + protocol.delay(minutes=0.1) + p1000.blow_out() + p1000.default_speed = 400 + p1000.move_to(Liquid_trash.top(z=-7)) + p1000.move_to(Liquid_trash.top(z=0)) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + for well_num in ["A1", "A2"]: + protocol.comment("--> ETOH Wash") + ETOHMaxVol = 150 + for loop, X in enumerate(column_5_list): + p1000.pick_up_tip() + p1000.aspirate(ETOHMaxVol, EtOH.bottom(z=1)) + p1000.move_to(EtOH.top(z=0)) + p1000.move_to(EtOH.top(z=-5)) + p1000.move_to(EtOH.top(z=0)) + p1000.move_to(sample_plate_2[well_num].top(z=-2)) + p1000.dispense(ETOHMaxVol, rate=1) + protocol.delay(minutes=0.1) + p1000.blow_out() + p1000.move_to(sample_plate_2[well_num].top(z=5)) + p1000.move_to(sample_plate_2[well_num].top(z=0)) + p1000.move_to(sample_plate_2[well_num].top(z=5)) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + if DRYRUN is False: + protocol.delay(minutes=0.5) + + protocol.comment("--> Remove ETOH Wash") + for loop, X in enumerate(column_5_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_2[X].bottom(z=3.5)) + p1000.aspirate(RemoveSup - 100, rate=0.25) + protocol.delay(minutes=0.1) + p1000.move_to(sample_plate_2[X].bottom(z=0.5)) + p1000.aspirate(100, rate=0.25) + p1000.default_speed = 5 + p1000.move_to(sample_plate_2[X].top(z=2)) + p1000.default_speed = 200 + p1000.dispense(200, Liquid_trash.top(z=-7)) + protocol.delay(minutes=0.1) + p1000.blow_out() + p1000.default_speed = 400 + p1000.move_to(Liquid_trash.top(z=-7)) + p1000.move_to(Liquid_trash.top(z=0)) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + if DRYRUN is False: + protocol.delay(minutes=2) + + protocol.comment("--> Removing Residual ETOH") + for loop, X in enumerate(column_5_list): + p1000.pick_up_tip() + p1000.move_to( + sample_plate_2[X].bottom(z=dot_bottom) + ) # original = (z=0) + p1000.aspirate(50, rate=0.25) + p1000.default_speed = 200 + p1000.dispense(50, Liquid_trash.top(z=-7)) + protocol.delay(minutes=0.1) + p1000.blow_out() + p1000.default_speed = 400 + p1000.move_to(Liquid_trash.top(z=-7)) + p1000.move_to(Liquid_trash.top(z=0)) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + + if DRYRUN is False: + protocol.delay(minutes=1) + + # ============================================================================================ + # GRIPPER MOVE PLATE FROM MAG PLATE TO HEATER SHAKER + helpers.move_labware_to_hs( + protocol, sample_plate_2, heatershaker, heatershaker + ) + + protocol.comment("--> Adding RSB") + RSBVol = 32 + RSBMixRep = 1 * 60 if DRYRUN is False else 0.1 * 60 + for loop, X in enumerate(column_5_list): + p1000.pick_up_tip() + p1000.aspirate(RSBVol, RSB.bottom(z=1)) + + p1000.move_to( + ( + sample_plate_2.wells_by_name()[X] + .center() + .move(types.Point(x=1.3 * 0.8, y=0, z=-4)) + ) + ) + p1000.dispense(RSBVol, rate=1) + p1000.move_to(sample_plate_2.wells_by_name()[X].bottom(z=1)) + p1000.aspirate(RSBVol, rate=1) + p1000.move_to( + ( + sample_plate_2.wells_by_name()[X] + .center() + .move(types.Point(x=0, y=1.3 * 0.8, z=-4)) + ) + ) + p1000.dispense(RSBVol, rate=1) + p1000.move_to(sample_plate_2.wells_by_name()[X].bottom(z=1)) + p1000.aspirate(RSBVol, rate=1) + p1000.move_to( + ( + sample_plate_2.wells_by_name()[X] + .center() + .move(types.Point(x=1.3 * -0.8, y=0, z=-4)) + ) + ) + p1000.dispense(RSBVol, rate=1) + p1000.move_to(sample_plate_2.wells_by_name()[X].bottom(z=1)) + p1000.aspirate(RSBVol, rate=1) + p1000.move_to( + ( + sample_plate_2.wells_by_name()[X] + .center() + .move(types.Point(x=0, y=1.3 * -0.8, z=-4)) + ) + ) + p1000.dispense(RSBVol, rate=1) + p1000.move_to(sample_plate_2.wells_by_name()[X].bottom(z=1)) + p1000.aspirate(RSBVol, rate=1) + p1000.dispense(RSBVol, rate=1) + + p1000.blow_out(sample_plate_2.wells_by_name()[X].center()) + p1000.move_to(sample_plate_2.wells_by_name()[X].top(z=5)) + p1000.move_to(sample_plate_2.wells_by_name()[X].top(z=0)) + p1000.move_to(sample_plate_2.wells_by_name()[X].top(z=5)) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + if DRYRUN is False: + heatershaker.set_and_wait_for_shake_speed( + rpm=(heater_shaker_speed * 0.8) + ) + protocol.delay(RSBMixRep) + heatershaker.deactivate_shaker() + + # ============================================================================================ + # GRIPPER MOVE PLATE FROM HEATER SHAKER TO MAG PLATE + helpers.move_labware_from_hs_to_destination( + protocol, sample_plate_2, heatershaker, mag_block + ) + + if DRYRUN is False: + protocol.delay(minutes=3) + + protocol.comment("--> Transferring Supernatant") + TransferSup = 30 + for loop, X in enumerate(column_5_list): + p1000.pick_up_tip() + p1000.move_to(sample_plate_2[X].bottom(z=0.5)) + p1000.aspirate(TransferSup + 1, rate=0.25) + p1000.dispense( + TransferSup + 1, sample_plate_1[column_6_list[loop]].bottom(z=1) + ) + p1000.return_tip() if TIP_TRASH is False else p1000.drop_tip() + p200_tips += 1 + tipcheck() + plate_reader_actions(protocol, plate_reader, hellma_plate) diff --git a/abr-testing/abr_testing/protocols/api 2.20/9_Magmax_RNA_Cells_Flex_csv.py b/abr-testing/abr_testing/protocols/active_protocols/9_Magmax_RNA_Cells_Flex.py similarity index 85% rename from abr-testing/abr_testing/protocols/api 2.20/9_Magmax_RNA_Cells_Flex_csv.py rename to abr-testing/abr_testing/protocols/active_protocols/9_Magmax_RNA_Cells_Flex.py index f4c94305bea..7b48972bb42 100644 --- a/abr-testing/abr_testing/protocols/api 2.20/9_Magmax_RNA_Cells_Flex_csv.py +++ b/abr-testing/abr_testing/protocols/active_protocols/9_Magmax_RNA_Cells_Flex.py @@ -16,6 +16,7 @@ import numpy as np from abr_testing.protocols import helpers +from typing import Dict metadata = { "author": "Zach Galluzzo ", @@ -57,29 +58,25 @@ # Start protocol def add_parameters(parameters: ParameterContext) -> None: """Parameters.""" - parameters.add_csv_file( - variable_name="parameters_csv", - display_name="Parameters CSV File", - description="CSV file containing parameters for this protocol", - ) + helpers.create_dot_bottom_parameter(parameters) + helpers.create_single_pipette_mount_parameter(parameters) + helpers.create_hs_speed_parameter(parameters) def run(ctx: ProtocolContext) -> None: """Protocol.""" dry_run = False inc_lysis = True - mount = "left" res_type = "nest_12_reservoir_15ml" TIP_TRASH = False num_samples = 48 - wash_vol = 150 - lysis_vol = 140 - stop_vol = 100 - elution_vol = dnase_vol = 50 - # default="\protocols\csv_parameters\9_parameters.csv", - csv_params = ctx.params.parameters_csv.parse_as_csv() # type: ignore[attr-defined] - heater_shaker_speed = int(csv_params[1][0]) - dot_bottom = csv_params[1][1] + wash_vol = 150.0 + lysis_vol = 140.0 + stop_vol = 100.0 + elution_vol = dnase_vol = 50.0 + heater_shaker_speed = ctx.params.heater_shaker_speed # type: ignore[attr-defined] + dot_bottom = ctx.params.dot_bottom # type: ignore[attr-defined] + pipette_mount = ctx.params.pipette_mount # type: ignore[attr-defined] # Protocol Parameters deepwell_type = "nest_96_wellplate_2ml_deep" @@ -95,28 +92,25 @@ def run(ctx: ProtocolContext) -> None: lysis_time = 0.25 drybeads = elute_time = 0.25 bind_time = wash_time = dnase_time = stop_time = 0.25 - bead_vol = 20 + bead_vol = 20.0 ctx.load_trash_bin("A3") h_s: HeaterShakerContext = ctx.load_module(helpers.hs_str, "D1") # type: ignore[assignment] - h_s_adapter = h_s.load_adapter("opentrons_96_deep_well_adapter") - sample_plate = h_s_adapter.load_labware(deepwell_type, "Sample Plate") + sample_plate, h_s_adapter = helpers.load_hs_adapter_and_labware( + deepwell_type, h_s, "Sample Plate" + ) h_s.close_labware_latch() temp: TemperatureModuleContext = ctx.load_module( helpers.temp_str, "D3" ) # type: ignore[assignment] - temp_block = temp.load_adapter("opentrons_96_well_aluminum_block") - elutionplate = temp_block.load_labware( - "armadilo_96_wellplate_200ul_pcr_full_skirt", "Elution Plate" + elutionplate, temp_adapter = helpers.load_temp_adapter_and_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", temp, "Elution Plate" ) temp.set_temperature(4) magblock: MagneticBlockContext = ctx.load_module( helpers.mag_str, "C1" ) # type: ignore[assignment] - waste = ( - ctx.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") - .wells()[0] - .top() - ) + waste_reservoir = ctx.load_labware("nest_1_reservoir_195ml", "B3", "Liquid Waste") + waste = waste_reservoir.wells()[0].top() res1 = ctx.load_labware(res_type, "D2", "reagent reservoir 1") num_cols = math.ceil(num_samples / 8) @@ -134,7 +128,11 @@ def run(ctx: ProtocolContext) -> None: tips_sn = tips200.wells()[:num_samples] # load P1000M pipette - m1000 = ctx.load_instrument("flex_8channel_1000", mount) + m1000 = ctx.load_instrument( + "flex_8channel_1000", + pipette_mount, + tip_racks=[tips200, tips201, tips202, tips203], + ) # Load Liquid Locations in Reservoir elution_solution = elutionplate.rows()[0][:num_cols] @@ -159,51 +157,24 @@ def run(ctx: ProtocolContext) -> None: elution_samps = elutionplate.wells()[: (8 * num_cols)] dnase1_ = elutionplate.wells()[(8 * num_cols) : (16 * num_cols)] - colors = helpers.liquid_colors - - locations = [lysis_, wash1, wash2, wash3, wash4, wash5, stopreaction] - vols = [lysis_vol, wash_vol, wash_vol, wash_vol, wash_vol, wash_vol, stop_vol] - liquids = ["Lysis", "Wash 1", "Wash 2", "Wash 3", "Wash 4", "Wash 5", "Stop"] - - dnase_liq = ctx.define_liquid( - name="DNAse", description="DNAse", display_color="#C0C0C0" - ) - eluate = ctx.define_liquid( - name="Elution Buffer", description="Elution Buffer", display_color="#00FF00" - ) - bead = ctx.define_liquid(name="Beads", description="Beads", display_color="#FFA500") - sample = ctx.define_liquid( - name="Sample", description="Cell Pellet", display_color="#FFC0CB" - ) - # Add liquids to non-reservoir labware - for i in beads_: - i.load_liquid(liquid=bead, volume=bead_vol) - for i in cells_: - i.load_liquid(liquid=sample, volume=0) - for i in dnase1_: - i.load_liquid(liquid=dnase_liq, volume=dnase_vol) - for i in elution_samps: - i.load_liquid(liquid=eluate, volume=elution_vol) - - delete = len(colors) - len(liquids) - - if delete >= 1: - for color_del in range(delete): - colors.pop(-1) - - def liquids_(liq: str, location: Well, color: str, vol: float) -> None: - """Define Liquids.""" - sampnum = 8 * (math.ceil(num_samples / 8)) - # Volume Calculation - extra_samples = math.ceil(1500 / vol) - - v = vol * (sampnum + extra_samples) - loaded_liq = ctx.define_liquid(name=liq, description=liq, display_color=color) - location.load_liquid(liquid=loaded_liq, volume=v) - - for x, (ll, l, c, v) in enumerate(zip(liquids, locations, colors, vols)): - liquids_(ll, l, c, v) + liquid_vols_and_wells: Dict[str, List[Dict[str, Well | List[Well] | float]]] = { + "Beads": [{"well": beads_, "volume": bead_vol}], + "Sample": [{"well": cells_, "volume": 0.0}], + "DNAse": [{"well": dnase1_, "volume": dnase_vol}], + "Elution Buffer": [{"well": elution_samps, "volume": elution_vol}], + "Lysis": [{"well": lysis_, "volume": lysis_vol}], + "Wash 1": [{"well": wash1, "volume": wash_vol}], + "Wash 2": [{"well": wash2, "volume": wash_vol}], + "Wash 3": [{"well": wash3, "volume": wash_vol}], + "Wash 4": [{"well": wash4, "volume": wash_vol}], + "Wash 5": [{"well": wash5, "volume": wash_vol}], + "Stop": [{"well": stopreaction, "volume": stop_vol}], + } + + flattened_list_of_wells = helpers.find_liquid_height_of_loaded_liquids( + ctx, liquid_vols_and_wells, m1000 + ) m1000.flow_rate.aspirate = 50 m1000.flow_rate.dispense = 150 @@ -389,7 +360,7 @@ def bind() -> None: helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, bind_time, True) # Transfer from H-S plate to Magdeck plate - helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) for bindi in np.arange( settling_time, 0, -0.5 @@ -422,7 +393,6 @@ def wash(vol: float, source: Well) -> None: vol_per_trans = vol / num_trans for i, m in enumerate(samples_m): src = source - m1000.require_liquid_presence(src) for n in range(num_trans): m1000.aspirate(vol_per_trans, src) m1000.air_gap(10) @@ -436,7 +406,7 @@ def wash(vol: float, source: Well) -> None: helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, wash_time, True) # Transfer from H-S plate to Magdeck plate - helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) for washi in np.arange( settling_time, 0, -0.5 @@ -502,7 +472,7 @@ def stop_reaction(vol: float, source: Well) -> None: helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, stop_time, True) # Transfer from H-S plate to Magdeck plate - helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) for stop in np.arange(settling_time, 0, -0.5): ctx.delay( @@ -545,7 +515,7 @@ def elute(vol: float) -> None: helpers.set_hs_speed(ctx, h_s, heater_shaker_speed, elute_time, True) # Transfer from H-S plate to Magdeck plate - helpers.move_labware_from_hs_to_mag_block(ctx, sample_plate, h_s, magblock) + helpers.move_labware_from_hs_to_destination(ctx, sample_plate, h_s, magblock) for elutei in np.arange(settling_time, 0, -0.5): ctx.delay( @@ -585,3 +555,6 @@ def elute(vol: float) -> None: msg="There are " + str(beaddry) + " minutes left in the drying step.", ) elute(elution_vol) + + flattened_list_of_wells.append(waste_reservoir["A1"]) + helpers.find_liquid_height_of_all_wells(ctx, m1000, flattened_list_of_wells) diff --git a/abr-testing/abr_testing/protocols/csv_parameters/3_samplevols.csv b/abr-testing/abr_testing/protocols/csv_parameters/3_samplevols.csv new file mode 100644 index 00000000000..bc952b330a1 --- /dev/null +++ b/abr-testing/abr_testing/protocols/csv_parameters/3_samplevols.csv @@ -0,0 +1,25 @@ +Sample_Plate, Sample_well,InitialVol,InitialConc,TargetConc +sample_plate,A2,10,3.94,1 +sample_plate,B2,10,3.5,1 +sample_plate,C2,10,3.46,1 +sample_plate,D2,10,3.1,1 +sample_plate,E2,10,2.64,1 +sample_plate,F2,10,3.16,1 +sample_plate,G2,10,2.9,1 +sample_plate,H2,10,2.8,1 +sample_plate,A3,10,2.82,1 +sample_plate,B3,10,2.84,1 +sample_plate,C3,10,2.72,1 +sample_plate,D3,10,2.9,1 +sample_plate,A5,10,3.94,1 +sample_plate,B5,10,3.5,1 +sample_plate,C5,10,3.46,1 +sample_plate,D5,10,3.1,1 +sample_plate,E5,10,2.64,1 +sample_plate,F5,10,3.16,1 +sample_plate,G5,10,2.9,1 +sample_plate,H5,10,2.8,1 +sample_plate,A6,10,2.82,1 +sample_plate,B6,10,2.84,1 +sample_plate,C6,10,2.72,1 +sample_plate,D6,10,2.9,1 diff --git a/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json b/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json new file mode 100644 index 00000000000..600f030583f --- /dev/null +++ b/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json @@ -0,0 +1,1127 @@ +{ + "ordering": [ + [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1" + ], + [ + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ], + [ + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3" + ], + [ + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4" + ], + [ + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5" + ], + [ + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6" + ], + [ + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7" + ], + [ + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8" + ], + [ + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9" + ], + [ + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10" + ], + [ + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ], + [ + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + ], + "brand": { + "brand": "Hellma", + "brandId": [ + "666-R013 Reference Plate" + ] + }, + "metadata": { + "displayName": "Hellma Reference Plate", + "displayCategory": "wellPlate", + "displayVolumeUnits": "µL", + "tags": [] + }, + "dimensions": { + "xDimension": 127, + "yDimension": 85.5, + "zDimension": 13 + }, + "wells": { + "A1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 74.26, + "z": 12 + }, + "B1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 65.26, + "z": 12 + }, + "C1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 56.26, + "z": 12 + }, + "D1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 47.26, + "z": 12 + }, + "E1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 38.26, + "z": 12 + }, + "F1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 29.26, + "z": 12 + }, + "G1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 20.26, + "z": 12 + }, + "H1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 11.26, + "z": 12 + }, + "A2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 74.26, + "z": 12 + }, + "B2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 65.26, + "z": 12 + }, + "C2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 56.26, + "z": 12 + }, + "D2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 47.26, + "z": 12 + }, + "E2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 38.26, + "z": 12 + }, + "F2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 29.26, + "z": 12 + }, + "G2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 20.26, + "z": 12 + }, + "H2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 11.26, + "z": 12 + }, + "A3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 74.26, + "z": 12 + }, + "B3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 65.26, + "z": 12 + }, + "C3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 56.26, + "z": 12 + }, + "D3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 47.26, + "z": 12 + }, + "E3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 38.26, + "z": 12 + }, + "F3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 29.26, + "z": 12 + }, + "G3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 20.26, + "z": 12 + }, + "H3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 11.26, + "z": 12 + }, + "A4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 74.26, + "z": 12 + }, + "B4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 65.26, + "z": 12 + }, + "C4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 56.26, + "z": 12 + }, + "D4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 47.26, + "z": 12 + }, + "E4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 38.26, + "z": 12 + }, + "F4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 29.26, + "z": 12 + }, + "G4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 20.26, + "z": 12 + }, + "H4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 11.26, + "z": 12 + }, + "A5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 74.26, + "z": 12 + }, + "B5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 65.26, + "z": 12 + }, + "C5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 56.26, + "z": 12 + }, + "D5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 47.26, + "z": 12 + }, + "E5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 38.26, + "z": 12 + }, + "F5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 29.26, + "z": 12 + }, + "G5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 20.26, + "z": 12 + }, + "H5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 11.26, + "z": 12 + }, + "A6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 74.26, + "z": 12 + }, + "B6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 65.26, + "z": 12 + }, + "C6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 56.26, + "z": 12 + }, + "D6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 47.26, + "z": 12 + }, + "E6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 38.26, + "z": 12 + }, + "F6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 29.26, + "z": 12 + }, + "G6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 20.26, + "z": 12 + }, + "H6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 11.26, + "z": 12 + }, + "A7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 74.26, + "z": 12 + }, + "B7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 65.26, + "z": 12 + }, + "C7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 56.26, + "z": 12 + }, + "D7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 47.26, + "z": 12 + }, + "E7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 38.26, + "z": 12 + }, + "F7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 29.26, + "z": 12 + }, + "G7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 20.26, + "z": 12 + }, + "H7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 11.26, + "z": 12 + }, + "A8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 74.26, + "z": 12 + }, + "B8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 65.26, + "z": 12 + }, + "C8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 56.26, + "z": 12 + }, + "D8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 47.26, + "z": 12 + }, + "E8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 38.26, + "z": 12 + }, + "F8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 29.26, + "z": 12 + }, + "G8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 20.26, + "z": 12 + }, + "H8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 11.26, + "z": 12 + }, + "A9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 74.26, + "z": 12 + }, + "B9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 65.26, + "z": 12 + }, + "C9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 56.26, + "z": 12 + }, + "D9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 47.26, + "z": 12 + }, + "E9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 38.26, + "z": 12 + }, + "F9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 29.26, + "z": 12 + }, + "G9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 20.26, + "z": 12 + }, + "H9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 11.26, + "z": 12 + }, + "A10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 74.26, + "z": 12 + }, + "B10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 65.26, + "z": 12 + }, + "C10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 56.26, + "z": 12 + }, + "D10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 47.26, + "z": 12 + }, + "E10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 38.26, + "z": 12 + }, + "F10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 29.26, + "z": 12 + }, + "G10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 20.26, + "z": 12 + }, + "H10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 11.26, + "z": 12 + }, + "A11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 74.26, + "z": 12 + }, + "B11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 65.26, + "z": 12 + }, + "C11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 56.26, + "z": 12 + }, + "D11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 47.26, + "z": 12 + }, + "E11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 38.26, + "z": 12 + }, + "F11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 29.26, + "z": 12 + }, + "G11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 20.26, + "z": 12 + }, + "H11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 11.26, + "z": 12 + }, + "A12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 74.26, + "z": 12 + }, + "B12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 65.26, + "z": 12 + }, + "C12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 56.26, + "z": 12 + }, + "D12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 47.26, + "z": 12 + }, + "E12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 38.26, + "z": 12 + }, + "F12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 29.26, + "z": 12 + }, + "G12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 20.26, + "z": 12 + }, + "H12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 11.26, + "z": 12 + } + }, + "groups": [ + { + "metadata": { + "wellBottomShape": "flat" + }, + "wells": [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1", + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2", + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3", + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4", + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5", + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6", + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7", + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8", + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9", + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10", + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11", + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] + } + ], + "parameters": { + "format": "irregular", + "quirks": [], + "isTiprack": false, + "isMagneticModuleCompatible": false, + "loadName": "hellma_reference_plate" + }, + "namespace": "custom_beta", + "version": 1, + "schemaVersion": 2, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } +} \ No newline at end of file diff --git a/abr-testing/abr_testing/protocols/helpers.py b/abr-testing/abr_testing/protocols/helpers.py index 6393ec9f1f9..e63cd0b5ce7 100644 --- a/abr-testing/abr_testing/protocols/helpers.py +++ b/abr-testing/abr_testing/protocols/helpers.py @@ -5,20 +5,26 @@ Labware, InstrumentContext, ParameterContext, + Well, ) from typing import Tuple from opentrons.protocol_api.module_contexts import ( HeaterShakerContext, MagneticBlockContext, ThermocyclerContext, + TemperatureModuleContext, ) -from typing import List +from typing import List, Union, Dict +from opentrons.hardware_control.modules.types import ThermocyclerStep +from opentrons_shared_data.errors.exceptions import PipetteLiquidNotFoundError + +# FUNCTIONS FOR LOADING COMMON CONFIGURATIONS def load_common_liquid_setup_labware_and_instruments( protocol: ProtocolContext, -) -> Tuple[Labware, InstrumentContext]: +) -> Tuple[Labware, Labware, InstrumentContext]: """Load Commonly used Labware and Instruments.""" # Tip rack tip_rack = protocol.load_labware("opentrons_flex_96_tiprack_1000ul", "D1") @@ -27,11 +33,72 @@ def load_common_liquid_setup_labware_and_instruments( instrument_name="flex_8channel_1000", mount="left", tip_racks=[tip_rack] ) # Source_reservoir - source_reservoir = protocol.load_labware("axygen_1_reservoir_90ml", "C2") - return source_reservoir, p1000 + source_reservoir = protocol.load_labware("nest_1_reservoir_290ml", "C2") + protocol.load_trash_bin("A3") + return source_reservoir, tip_rack, p1000 + + +def load_disposable_lids( + protocol: ProtocolContext, num_of_lids: int, deck_slot: List[str] +) -> List[Labware]: + """Load Stack of Disposable lids.""" + unused_lids = [ + protocol.load_labware("opentrons_tough_pcr_auto_sealing_lid", deck_slot[0]) + ] + if len(deck_slot) == 1: + for i in range(num_of_lids - 1): + unused_lids.append( + unused_lids[-1].load_labware("opentrons_tough_pcr_auto_sealing_lid") + ) + else: + for i in range(len(deck_slot) - 1): + unused_lids.append( + protocol.load_labware( + "opentrons_tough_pcr_auto_sealing_lid", deck_slot[i] + ) + ) + unused_lids.reverse() + return unused_lids + + +def load_hs_adapter_and_labware( + labware_str: str, heatershaker: HeaterShakerContext, labware_name: str +) -> Tuple[Labware, Labware]: + """Load appropriate adapter on heatershaker based off labware type.""" + heatershaker_adapters = { + "nest_96_wellplate_2ml_deep": "opentrons_96_deep_well_adapter", + "armadillo_96_wellplate_200ul_pcr_full_skirt": "opentrons_96_pcr_adapter", + } + hs_adapter_type = heatershaker_adapters.get(labware_str, "") + if hs_adapter_type: + hs_adapter = heatershaker.load_adapter(hs_adapter_type) + labware_on_hs = hs_adapter.load_labware(labware_str, labware_name) + else: + heatershaker.load_labware(labware_str, labware_name) + return labware_on_hs, hs_adapter + + +def load_temp_adapter_and_labware( + labware_str: str, temp_mod: TemperatureModuleContext, labware_name: str +) -> Tuple[Labware, Labware]: + """Load appropriate adapter on temperature module based off labware type.""" + temp_mod_adapters = { + "nest_96_wellplate_2ml_deep": "opentrons_96_deep_well_temp_mod_adapter", + "armadillo_96_wellplate_200ul_pcr_full_skirt": "opentrons_96_well_aluminum_block", + } + temp_adapter_type = temp_mod_adapters.get(labware_str, "") + if temp_adapter_type: + temp_adapter = temp_mod.load_adapter(temp_adapter_type) + labware_on_temp_mod = temp_adapter.load_labware(labware_str, labware_name) + else: + labware_on_temp_mod = temp_mod.load_labware(labware_str, labware_name) + return labware_on_temp_mod, temp_adapter + +# FUNCTIONS FOR LOADING COMMON PARAMETERS -def create_pipette_mount_parameter(parameters: ParameterContext) -> None: + +def create_single_pipette_mount_parameter(parameters: ParameterContext) -> None: """Create parameter to specify pipette mount.""" parameters.add_str( variable_name="pipette_mount", @@ -44,6 +111,37 @@ def create_pipette_mount_parameter(parameters: ParameterContext) -> None: ) +def create_two_pipette_mount_parameters(parameters: ParameterContext) -> None: + """Create mount parameters for 2 pipettes.""" + parameters.add_str( + variable_name="pipette_mount_1", + display_name="Pipette Mount 1", + choices=[ + {"display_name": "Left", "value": "left"}, + {"display_name": "Right", "value": "right"}, + ], + default="left", + ) + parameters.add_str( + variable_name="pipette_mount_2", + display_name="Pipette Mount 2", + choices=[ + {"display_name": "Left", "value": "left"}, + {"display_name": "Right", "value": "right"}, + ], + default="right", + ) + + +def create_csv_parameter(parameters: ParameterContext) -> None: + """Create parameter for sample volume csvs.""" + parameters.add_csv_file( + variable_name="parameters_csv", + display_name="Sample CSV", + description="CSV File for Protocol.", + ) + + def create_disposable_lid_parameter(parameters: ParameterContext) -> None: """Create parameter to use/not use disposable lid.""" parameters.add_bool( @@ -75,7 +173,7 @@ def create_dot_bottom_parameter(parameters: ParameterContext) -> None: variable_name="dot_bottom", display_name=".bottom", description="Lowest value pipette will go to.", - default=0.5, + default=0.3, choices=[ {"display_name": "0.0", "value": 0.0}, {"display_name": "0.1", "value": 0.1}, @@ -105,15 +203,18 @@ def create_hs_speed_parameter(parameters: ParameterContext) -> None: ) -def move_labware_from_hs_to_mag_block( +# FUNCTIONS FOR COMMON MODULE SEQUENCES + + +def move_labware_from_hs_to_destination( protocol: ProtocolContext, labware_to_move: Labware, hs: HeaterShakerContext, - mag_block: MagneticBlockContext, + new_module: Union[MagneticBlockContext, ThermocyclerContext], ) -> None: """Move labware from heatershaker to magnetic block.""" hs.open_labware_latch() - protocol.move_labware(labware_to_move, mag_block, use_gripper=True) + protocol.move_labware(labware_to_move, new_module, use_gripper=True) hs.close_labware_latch() @@ -121,7 +222,7 @@ def move_labware_to_hs( protocol: ProtocolContext, labware_to_move: Labware, hs: HeaterShakerContext, - hs_adapter: Labware, + hs_adapter: Union[Labware, HeaterShakerContext], ) -> None: """Move labware to heatershaker.""" hs.open_labware_latch() @@ -137,6 +238,7 @@ def set_hs_speed( deactivate: bool, ) -> None: """Set heatershaker for a speed and duration.""" + hs.close_labware_latch() hs.set_and_wait_for_shake_speed(hs_speed) protocol.delay( minutes=time_min, @@ -146,29 +248,6 @@ def set_hs_speed( hs.deactivate_shaker() -def load_disposable_lids( - protocol: ProtocolContext, num_of_lids: int, deck_slot: List[str] -) -> List[Labware]: - """Load Stack of Disposable lids.""" - unused_lids = [ - protocol.load_labware("opentrons_tough_pcr_auto_sealing_lid", deck_slot[0]) - ] - if len(deck_slot) == 1: - for i in range(num_of_lids - 1): - unused_lids.append( - unused_lids[-1].load_labware("opentrons_tough_pcr_auto_sealing_lid") - ) - else: - for i in range(len(deck_slot) - 1): - unused_lids.append( - protocol.load_labware( - "opentrons_tough_pcr_auto_sealing_lid", deck_slot[i] - ) - ) - unused_lids.reverse() - return unused_lids - - def use_disposable_lid_with_tc( protocol: ProtocolContext, unused_lids: List[Labware], @@ -186,8 +265,138 @@ def use_disposable_lid_with_tc( return lid_on_plate, unused_lids, used_lids +# FUNCTIONS FOR COMMON PIPETTE COMMAND SEQUENCES + + +def find_liquid_height(pipette: InstrumentContext, well_to_probe: Well) -> float: + """Find liquid height of well.""" + try: + liquid_height = ( + pipette.measure_liquid_height(well_to_probe) + - well_to_probe.bottom().point.z + ) + except PipetteLiquidNotFoundError: + liquid_height = 0 + return liquid_height + + +def load_wells_with_custom_liquids( + protocol: ProtocolContext, + liquid_vols_and_wells: Dict[str, List[Dict[str, Union[Well, List[Well], float]]]], +) -> None: + """Load custom liquids into wells.""" + liquid_colors = [ + "#008000", + "#A52A2A", + "#00FFFF", + "#0000FF", + "#800080", + "#ADD8E6", + "#FF0000", + "#FFFF00", + "#FF00FF", + "#00008B", + "#7FFFD4", + "#FFC0CB", + "#FFA500", + "#00FF00", + "#C0C0C0", + ] + i = 0 + volume = 0.0 + for liquid_name, wells_info in liquid_vols_and_wells.items(): + # Define the liquid with a color + liquid = protocol.define_liquid( + liquid_name, display_color=liquid_colors[i % len(liquid_colors)] + ) + i += 1 + # Load liquid into each specified well or list of wells + for well_info in wells_info: + if isinstance(well_info["well"], list): + wells = well_info["well"] + elif isinstance(well_info["well"], Well): + wells = [well_info["well"]] + else: + wells = [] + if isinstance(well_info["volume"], float): + volume = well_info["volume"] + + # Load liquid into each well + for well in wells: + well.load_liquid(liquid, volume) + + +def find_liquid_height_of_all_wells( + protocol: ProtocolContext, + pipette: InstrumentContext, + wells: List[Well], +) -> Dict: + """Find the liquid height of all wells in protocol.""" + dict_of_labware_heights = {} + pipette.pick_up_tip() + for well in wells: + labware_name = well.parent.load_name + total_number_of_wells_in_plate = len(well.parent.wells()) + pip_channels = pipette.active_channels + # if pip_channels is > 1 and total_wells > 12 - only probe 1st row. + if ( + pip_channels > 1 + and total_number_of_wells_in_plate > 12 + and well.well_name.startswith("A") + ): + liquid_height_of_well = find_liquid_height(pipette, well) + dict_of_labware_heights[labware_name, well] = liquid_height_of_well + elif total_number_of_wells_in_plate <= 12: + liquid_height_of_well = find_liquid_height(pipette, well) + dict_of_labware_heights[labware_name, well] = liquid_height_of_well + if pip_channels == pipette.channels: + pipette.return_tip() + pipette.reset_tipracks() + else: + pipette.drop_tip() + msg = f"result: {dict_of_labware_heights}" + protocol.comment(msg=msg) + return dict_of_labware_heights + + +def find_liquid_height_of_loaded_liquids( + ctx: ProtocolContext, + liquid_vols_and_wells: Dict[str, List[Dict[str, Union[Well, List[Well], float]]]], + pipette: InstrumentContext, +) -> List[Well]: + """Find Liquid height of loaded liquids.""" + load_wells_with_custom_liquids(ctx, liquid_vols_and_wells) + # Get flattened list of wells. + wells: list[Well] = [ + well + for items in liquid_vols_and_wells.values() + for entry in items + if isinstance(entry["well"], (Well, list)) and entry["volume"] != 0 + # Ensure "well" is Well or list of Well + for well in ( + entry["well"] if isinstance(entry["well"], list) else [entry["well"]] + ) + ] + find_liquid_height_of_all_wells(ctx, pipette, wells) + return wells + + +def load_wells_with_water( + protocol: ProtocolContext, wells: List[Well], volumes: List[float] +) -> None: + """Load liquids into wells.""" + water = protocol.define_liquid("Water", display_color="#0000FF") + for well, volume in zip(wells, volumes): + well.load_liquid(water, volume) + + # CONSTANTS +hs_str = "heaterShakerModuleV1" +mag_str = "magneticBlockV1" +temp_str = "temperature module gen2" +tc_str = "thermocycler module gen2" +abs_mod_str = "absorbanceReaderV1" liquid_colors = [ "#008000", "#008000", @@ -208,11 +417,44 @@ def use_disposable_lid_with_tc( "#C0C0C0", ] -hs_adapter_str = "opentrons_96_pcr_adapter" -hs_str = "heaterShakerModuleV1" -mag_str = "magneticBlockV1" -temp_adapter_str = "opentrons_96_well_aluminum_block" -temp_str = "temperature module gen2" -tc_str = "thermocycler module gen2" +# THERMOCYCLER PROFILES + + +def perform_pcr( + protocol: ProtocolContext, + thermocycler: ThermocyclerContext, + initial_denature_time_sec: int, + denaturation_time_sec: int, + anneal_time_sec: int, + extension_time_sec: int, + cycle_repetitions: int, + final_extension_time_min: int, +) -> None: + """Perform PCR.""" + # Define profiles. + initial_denaturation_profile: List[ThermocyclerStep] = [ + {"temperature": 98, "hold_time_seconds": initial_denature_time_sec} + ] + cycling_profile: List[ThermocyclerStep] = [ + {"temperature": 98, "hold_time_seconds": denaturation_time_sec}, + {"temperature": 60, "hold_time_seconds": anneal_time_sec}, + {"temperature": 72, "hold_time_seconds": extension_time_sec}, + ] + final_extension_profile: List[ThermocyclerStep] = [ + {"temperature": 72, "hold_time_minutes": final_extension_time_min} + ] + protocol.comment(f"Initial Denaturation for {initial_denature_time_sec} seconds.") + thermocycler.execute_profile( + steps=initial_denaturation_profile, repetitions=1, block_max_volume=50 + ) + protocol.comment(f"PCR for {cycle_repetitions} cycles.") + thermocycler.execute_profile( + steps=cycling_profile, repetitions=cycle_repetitions, block_max_volume=50 + ) + protocol.comment(f"Final Extension profile for {final_extension_time_min} minutes.") + thermocycler.execute_profile( + steps=final_extension_profile, repetitions=1, block_max_volume=50 + ) + # TODO: Create dictionary of labware, module, and adapter. diff --git a/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py index c2c4727d9df..e5c70194afa 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/10_ZymoBIOMICS Magbead Liquid Setup.py @@ -20,7 +20,11 @@ def run(protocol: protocol_api.ProtocolContext) -> None: """Protocol.""" # Initiate Labware - source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + ( + source_reservoir, + tip_rack, + p1000, + ) = load_common_liquid_setup_labware_and_instruments(protocol) res1 = protocol.load_labware("nest_12_reservoir_15ml", "C3", "R1") res2 = protocol.load_labware("nest_12_reservoir_15ml", "B3", "R2") diff --git a/abr-testing/abr_testing/protocols/liquid_setups/11_Dynabeads RIT Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/11_Dynabeads RIT Liquid Setup.py index 81316be63e3..112aec315b5 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/11_Dynabeads RIT Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/11_Dynabeads RIT Liquid Setup.py @@ -20,7 +20,11 @@ def run(protocol: protocol_api.ProtocolContext) -> None: """Protocol.""" # Deck Setup - source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + ( + source_reservoir, + tip_rack, + p1000, + ) = load_common_liquid_setup_labware_and_instruments(protocol) reservoir_wash = protocol.load_labware("nest_12_reservoir_15ml", "D2", "Reservoir") sample_plate = protocol.load_labware( diff --git a/abr-testing/abr_testing/protocols/liquid_setups/12_KAPA HyperPlus Library Prep Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/12_KAPA HyperPlus Library Prep Liquid Setup.py index d27693df67e..b4282397baf 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/12_KAPA HyperPlus Library Prep Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/12_KAPA HyperPlus Library Prep Liquid Setup.py @@ -19,7 +19,11 @@ def run(protocol: protocol_api.ProtocolContext) -> None: """Protocol.""" - source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + ( + source_reservoir, + tip_rack, + p1000, + ) = load_common_liquid_setup_labware_and_instruments(protocol) reservoir = protocol.load_labware("nest_96_wellplate_2ml_deep", "D2") # Reservoir temp_module_res = protocol.load_labware( diff --git a/abr-testing/abr_testing/protocols/liquid_setups/1_Simple normalize long Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/1_Simple normalize long Liquid Setup.py index e0a75adfe84..2d995fede39 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/1_Simple normalize long Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/1_Simple normalize long Liquid Setup.py @@ -19,7 +19,11 @@ def run(protocol: protocol_api.ProtocolContext) -> None: """Protocol.""" # Initiate Labware - source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + ( + source_reservoir, + tip_rack, + p1000, + ) = load_common_liquid_setup_labware_and_instruments(protocol) reservoir = protocol.load_labware("nest_12_reservoir_15ml", "D2", "Reservoir") # Transfer Liquid vol = 5400 / 8 diff --git a/abr-testing/abr_testing/protocols/liquid_setups/2_BMS_PCR_protocol Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/2_BMS_PCR_protocol Liquid Setup.py index c374a586532..a6c71b563d4 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/2_BMS_PCR_protocol Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/2_BMS_PCR_protocol Liquid Setup.py @@ -20,14 +20,22 @@ def run(protocol: protocol_api.ProtocolContext) -> None: """Protocol.""" # Initiate Labware - source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) - pcr_plate_1 = protocol.load_labware("nest_12_reservoir_15ml", "C3", "PCR Plate 1") - pcr_plate_2 = protocol.load_labware("nest_12_reservoir_15ml", "B3", "PCR Plate 2") + ( + source_reservoir, + tip_rack, + p1000, + ) = load_common_liquid_setup_labware_and_instruments(protocol) + pcr_plate_1 = protocol.load_labware( + "armadillo_96_wellplate_200ul_pcr_full_skirt", "C3", "PCR Plate 1" + ) + snap_caps = protocol.load_labware( + "opentrons_24_aluminumblock_nest_1.5ml_snapcap", "B3", "Snap Caps" + ) # Steps - p1000.pick_up_tip() - p1000.aspirate(200, source_reservoir["A1"]) # Dispense into plate 1 - p1000.dispense(100, pcr_plate_1["A1"].top()) - # Dispense into plate 2 - p1000.dispense(100, pcr_plate_2["A1"].top()) - p1000.return_tip() + p1000.transfer(50, source_reservoir["A1"], pcr_plate_1.wells(), trash=False) + + # Dispense + p1000.configure_nozzle_layout(protocol_api.SINGLE, start="H1", tip_racks=[tip_rack]) + p1000.transfer(1500, source_reservoir["A1"], snap_caps["B1"]) + p1000.transfer(1500, source_reservoir["A1"], snap_caps.rows()[0]) diff --git a/abr-testing/abr_testing/protocols/liquid_setups/3_OT3 ABR Normalize with Tubes Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/3_OT3 ABR Normalize with Tubes Liquid Setup.py new file mode 100644 index 00000000000..86e4de2aeed --- /dev/null +++ b/abr-testing/abr_testing/protocols/liquid_setups/3_OT3 ABR Normalize with Tubes Liquid Setup.py @@ -0,0 +1,40 @@ +"""Plate Filler Protocol for Simple Normalize Long.""" +from opentrons import protocol_api +from abr_testing.protocols.helpers import ( + load_common_liquid_setup_labware_and_instruments, +) + +metadata = { + "protocolName": "DVT1ABR3 Liquids: Flex Normalize with Tubes", + "author": "Rhyann clarke ", + "source": "Protocol Library", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.20", +} + + +def run(protocol: protocol_api.ProtocolContext) -> None: + """Protocol.""" + # Initiate Labware + ( + source_reservoir, + tip_rack, + p1000, + ) = load_common_liquid_setup_labware_and_instruments(protocol) + reagent_tube = protocol.load_labware( + "opentrons_10_tuberack_falcon_4x50ml_6x15ml_conical", "D3", "Reagent Tube" + ) + p1000.configure_nozzle_layout( + style=protocol_api.SINGLE, start="H1", tip_racks=[tip_rack] + ) + # Transfer Liquid + p1000.transfer( + 4000, + source_reservoir["A1"], + reagent_tube["A1"].top(), + blowout=True, + blowout_location="source well", + ) diff --git a/abr-testing/abr_testing/protocols/liquid_setups/4_Illumina DNA Enrichment Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/4_Illumina DNA Enrichment Liquid Setup.py index dee32fd5e4c..18aee383ace 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/4_Illumina DNA Enrichment Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/4_Illumina DNA Enrichment Liquid Setup.py @@ -18,16 +18,20 @@ def run(protocol: protocol_api.ProtocolContext) -> None: """Protocol.""" - source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + ( + source_reservoir, + tip_rack, + p1000, + ) = load_common_liquid_setup_labware_and_instruments(protocol) reservoir_1 = protocol.load_labware( "nest_96_wellplate_2ml_deep", "D2", "Reservoir 1" ) # Reservoir reservoir_2 = protocol.load_labware( - "thermoscientificnunc_96_wellplate_1300ul", "D3", "Reservoir 2" + "thermoscientificnunc_96_wellplate_1300ul", "D3", "Sample Plate 2" ) # Reservoir sample_plate_1 = protocol.load_labware( - "armadillo_96_wellplate_200ul_pcr_full_skirt", "C3", "Sample Plate" + "armadillo_96_wellplate_200ul_pcr_full_skirt", "C3", "Sample Plate 1" ) # Sample Plate reagent_plate_1 = protocol.load_labware( "armadillo_96_wellplate_200ul_pcr_full_skirt", "B3", "Reagent Plate" diff --git a/abr-testing/abr_testing/protocols/liquid_setups/5_96ch Complex Protocol Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/5_96ch Complex Protocol Liquid Setup.py index c1c54e5b2c9..cd263318442 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/5_96ch Complex Protocol Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/5_96ch Complex Protocol Liquid Setup.py @@ -19,7 +19,11 @@ def run(protocol: protocol_api.ProtocolContext) -> None: """Protocol.""" # Initiate Labware - source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + ( + source_reservoir, + tip_rack, + p1000, + ) = load_common_liquid_setup_labware_and_instruments(protocol) reservoir = protocol.load_labware( "nest_96_wellplate_2ml_deep", "D2", "Reservoir" diff --git a/abr-testing/abr_testing/protocols/liquid_setups/7_HDQ DNA Bacteria Extraction Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/7_HDQ DNA Bacteria Extraction Liquid Setup.py index f4188e4d3d8..410e46fd9bb 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/7_HDQ DNA Bacteria Extraction Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/7_HDQ DNA Bacteria Extraction Liquid Setup.py @@ -20,7 +20,11 @@ def run(protocol: protocol_api.ProtocolContext) -> None: """Protocol.""" # Deck Setup - source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + ( + source_reservoir, + tip_rack, + p1000, + ) = load_common_liquid_setup_labware_and_instruments(protocol) sample_plate = protocol.load_labware( "nest_96_wellplate_2ml_deep", "C3", "Sample Plate" diff --git a/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py index 9ccde013920..b32abb1f81d 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py @@ -20,7 +20,11 @@ def run(protocol: protocol_api.ProtocolContext) -> None: """Protocol.""" # Initiate Labware - source_reservoir, p1000 = load_common_liquid_setup_labware_and_instruments(protocol) + ( + source_reservoir, + tip_rack, + p1000, + ) = load_common_liquid_setup_labware_and_instruments(protocol) res1 = protocol.load_labware("nest_12_reservoir_15ml", "D2", "Reservoir") elution_plate = protocol.load_labware( "opentrons_96_wellplate_200ul_pcr_full_skirt", "C3", "Elution Plate" diff --git a/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py b/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py index 63e40519fac..df85453ff28 100644 --- a/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py +++ b/abr-testing/abr_testing/protocols/test_protocols/tc_lid_x_offset_test.py @@ -2,7 +2,6 @@ from opentrons.protocol_api import ( ParameterContext, ProtocolContext, - Labware, ) from opentrons.protocol_api.module_contexts import ( ThermocyclerContext, @@ -48,16 +47,14 @@ def add_parameters(parameters: ParameterContext) -> None: {"display_name": "1.8", "value": 1.8}, {"display_name": "1.9", "value": 1.9}, {"display_name": "2", "value": 2}, - - ], default=2, ) parameters.add_bool( - variable_name = "negative", - display_name = "Negative", - description = "Turn on to make offset negative.", - default = False + variable_name="negative", + display_name="Negative", + description="Turn on to make offset negative.", + default=False, ) @@ -66,7 +63,7 @@ def run(protocol: ProtocolContext) -> None: # Load Parameters lids_in_stack = protocol.params.lids_in_a_stack # type: ignore[attr-defined] x_offset = protocol.params.x_offset # type: ignore[attr-defined] - negative = protocol.params.negative # type: ignore[attr-defined] + negative = protocol.params.negative # type: ignore[attr-defined] if negative: x_offset = x_offset * -1 # Thermocycler @@ -83,13 +80,13 @@ def run(protocol: ProtocolContext) -> None: lid_stack_3 = helpers.load_disposable_lids(protocol, lids_in_stack, ["B2"]) lid_stack_4 = helpers.load_disposable_lids(protocol, lids_in_stack, ["C3"]) lid_stack_5 = helpers.load_disposable_lids(protocol, lids_in_stack, ["B3"]) - + drop_offset = {"x": x_offset, "y": 0, "z": 0} slot = 0 lids = [lid_stack_1, lid_stack_2, lid_stack_3, lid_stack_4, lid_stack_5] for lid_list in lids: lid_to_move = lid_list[0] - + lid_to_move_back_to = lid_list[1] protocol.comment(f"Offset {x_offset}, Lid # {slot+1}") # move lid to plate in thermocycler @@ -97,4 +94,3 @@ def run(protocol: ProtocolContext) -> None: lid_to_move, plate_in_cycler, use_gripper=True, drop_offset=drop_offset ) protocol.move_labware(lid_to_move, lid_to_move_back_to, use_gripper=True) - From 1bdf055e19135ce77e4e79aa1b0f7fa5b7088a90 Mon Sep 17 00:00:00 2001 From: rclarke0 Date: Thu, 7 Nov 2024 16:19:41 -0500 Subject: [PATCH 08/13] format fix on json file --- abr-testing/Pipfile | 1 + abr-testing/Pipfile.lock | 326 +++++++++--------- .../hellma_reference_plate.json | 2 +- 3 files changed, 169 insertions(+), 160 deletions(-) diff --git a/abr-testing/Pipfile b/abr-testing/Pipfile index 90534f708ae..613ca5203f7 100644 --- a/abr-testing/Pipfile +++ b/abr-testing/Pipfile @@ -19,6 +19,7 @@ slack-sdk = "*" pandas = "*" pandas-stubs = "*" paramiko = "*" +prettier = "*" [dev-packages] atomicwrites = "==1.4.1" diff --git a/abr-testing/Pipfile.lock b/abr-testing/Pipfile.lock index 79885cdc940..a1b677f52bb 100644 --- a/abr-testing/Pipfile.lock +++ b/abr-testing/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a537d1f1a5f5d0658a3ba2c62deabf390fd7b9e72acbee6704f8d095c1b535e9" + "sha256": "f773f4880fa452637eeaf5e1aebee4ca6a1dc34907f588e0c6f71f0f222dc725" }, "pipfile-spec": 6, "requires": { @@ -555,28 +555,28 @@ }, "google-api-core": { "hashes": [ - "sha256:4a152fd11a9f774ea606388d423b68aa7e6d6a0ffe4c8266f74979613ec09f81", - "sha256:6869eacb2a37720380ba5898312af79a4d30b8bca1548fb4093e0697dc4bdf5d" + "sha256:26f8d76b96477db42b55fd02a33aae4a42ec8b86b98b94969b7333a2c828bf35", + "sha256:a6652b6bd51303902494998626653671703c420f6f4c88cfd3f50ed723e9d021" ], "markers": "python_version >= '3.7'", - "version": "==2.21.0" + "version": "==2.22.0" }, "google-api-python-client": { "hashes": [ - "sha256:1a5232e9cfed8c201799d9327e4d44dc7ea7daa3c6e1627fca41aa201539c0da", - "sha256:b9d68c6b14ec72580d66001bd33c5816b78e2134b93ccc5cf8f624516b561750" + "sha256:4427b2f47cd88b0355d540c2c52215f68c337f3bc9d6aae1ceeae4525977504c", + "sha256:a9d26d630810ed4631aea21d1de3e42072f98240aaf184a8a1a874a371115034" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==2.149.0" + "version": "==2.151.0" }, "google-auth": { "hashes": [ - "sha256:25df55f327ef021de8be50bad0dfd4a916ad0de96da86cd05661c9297723ad3f", - "sha256:f4c64ed4e01e8e8b646ef34c018f8bf3338df0c8e37d8b3bba40e7f574a3278a" + "sha256:51a15d47028b66fd36e5c64a82d2d57480075bccc7da37cde257fc94177a61fb", + "sha256:545e9618f2df0bcbb7dcbc45a546485b1212624716975a1ea5ae8149ce769ab1" ], "markers": "python_version >= '3.7'", - "version": "==2.35.0" + "version": "==2.36.0" }, "google-auth-httplib2": { "hashes": [ @@ -776,7 +776,7 @@ "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3", "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f" ], - "markers": "python_version >= '3.9'", + "markers": "python_version < '3.11'", "version": "==1.26.4" }, "oauth2client": { @@ -890,6 +890,14 @@ "markers": "python_version >= '3.6'", "version": "==3.5.0" }, + "prettier": { + "hashes": [ + "sha256:20e76791de41cafe481328dd49552303f29ca192151cee1b120c26f66cae9bfc", + "sha256:6c34b8cd09fd9c8956c05d6395ea3f575e0122dce494ba57685c07065abed427" + ], + "index": "pypi", + "version": "==0.0.7" + }, "propcache": { "hashes": [ "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9", @@ -996,11 +1004,11 @@ }, "proto-plus": { "hashes": [ - "sha256:30b72a5ecafe4406b0d339db35b56c4059064e69227b8c3bda7462397f966445", - "sha256:402576830425e5f6ce4c2a6702400ac79897dab0b4343821aa5188b0fab81a12" + "sha256:c91fc4a65074ade8e458e95ef8bac34d4008daa7cce4a12d6707066fca648961", + "sha256:fbb17f57f7bd05a68b7707e745e26528b0b3c34e378db91eef93912c54982d91" ], "markers": "python_version >= '3.7'", - "version": "==1.24.0" + "version": "==1.25.0" }, "protobuf": { "hashes": [ @@ -1045,52 +1053,52 @@ }, "pydantic": { "hashes": [ - "sha256:069b9c9fc645474d5ea3653788b544a9e0ccd3dca3ad8c900c4c6eac844b4620", - "sha256:06a189b81ffc52746ec9c8c007f16e5167c8b0a696e1a726369327e3db7b2a82", - "sha256:11d9d9b87b50338b1b7de4ebf34fd29fdb0d219dc07ade29effc74d3d2609c62", - "sha256:15fdbe568beaca9aacfccd5ceadfb5f1a235087a127e8af5e48df9d8a45ae85c", - "sha256:19a3bd00b9dafc2cd7250d94d5b578edf7a0bd7daf102617153ff9a8fa37871c", - "sha256:23e8ec1ce4e57b4f441fc91e3c12adba023fedd06868445a5b5f1d48f0ab3682", - "sha256:24a4a159d0f7a8e26bf6463b0d3d60871d6a52eac5bb6a07a7df85c806f4c048", - "sha256:2ce3fcf75b2bae99aa31bd4968de0474ebe8c8258a0110903478bd83dfee4e3b", - "sha256:335a32d72c51a313b33fa3a9b0fe283503272ef6467910338e123f90925f0f03", - "sha256:3445426da503c7e40baccefb2b2989a0c5ce6b163679dd75f55493b460f05a8f", - "sha256:34a3613c7edb8c6fa578e58e9abe3c0f5e7430e0fc34a65a415a1683b9c32d9a", - "sha256:3d5492dbf953d7d849751917e3b2433fb26010d977aa7a0765c37425a4026ff1", - "sha256:44ae8a3e35a54d2e8fa88ed65e1b08967a9ef8c320819a969bfa09ce5528fafe", - "sha256:467a14ee2183bc9c902579bb2f04c3d3dac00eff52e252850509a562255b2a33", - "sha256:46f379b8cb8a3585e3f61bf9ae7d606c70d133943f339d38b76e041ec234953f", - "sha256:49e26c51ca854286bffc22b69787a8d4063a62bf7d83dc21d44d2ff426108518", - "sha256:65f7361a09b07915a98efd17fdec23103307a54db2000bb92095457ca758d485", - "sha256:6951f3f47cb5ca4da536ab161ac0163cab31417d20c54c6de5ddcab8bc813c3f", - "sha256:72fa46abace0a7743cc697dbb830a41ee84c9db8456e8d77a46d79b537efd7ec", - "sha256:74fe19dda960b193b0eb82c1f4d2c8e5e26918d9cda858cbf3f41dd28549cb70", - "sha256:7a4c5eec138a9b52c67f664c7d51d4c7234c5ad65dd8aacd919fb47445a62c86", - "sha256:80b982d42515632eb51f60fa1d217dfe0729f008e81a82d1544cc392e0a50ddf", - "sha256:941a2eb0a1509bd7f31e355912eb33b698eb0051730b2eaf9e70e2e1589cae1d", - "sha256:9f463abafdc92635da4b38807f5b9972276be7c8c5121989768549fceb8d2588", - "sha256:a00e63104346145389b8e8f500bc6a241e729feaf0559b88b8aa513dd2065481", - "sha256:aad8771ec8dbf9139b01b56f66386537c6fe4e76c8f7a47c10261b69ad25c2c9", - "sha256:ae6fa2008e1443c46b7b3a5eb03800121868d5ab6bc7cda20b5df3e133cde8b3", - "sha256:b661ce52c7b5e5f600c0c3c5839e71918346af2ef20062705ae76b5c16914cab", - "sha256:b74be007703547dc52e3c37344d130a7bfacca7df112a9e5ceeb840a9ce195c7", - "sha256:baebdff1907d1d96a139c25136a9bb7d17e118f133a76a2ef3b845e831e3403a", - "sha256:c20f682defc9ef81cd7eaa485879ab29a86a0ba58acf669a78ed868e72bb89e0", - "sha256:c3e742f62198c9eb9201781fbebe64533a3bbf6a76a91b8d438d62b813079dbc", - "sha256:c5ae6b7c8483b1e0bf59e5f1843e4fd8fd405e11df7de217ee65b98eb5462861", - "sha256:c6d0a9f9eccaf7f438671a64acf654ef0d045466e63f9f68a579e2383b63f357", - "sha256:cbfbca662ed3729204090c4d09ee4beeecc1a7ecba5a159a94b5a4eb24e3759a", - "sha256:d5389eb3b48a72da28c6e061a247ab224381435256eb541e175798483368fdd3", - "sha256:e306e280ebebc65040034bff1a0a81fd86b2f4f05daac0131f29541cafd80b80", - "sha256:e405ffcc1254d76bb0e760db101ee8916b620893e6edfbfee563b3c6f7a67c02", - "sha256:e9ee4e6ca1d9616797fa2e9c0bfb8815912c7d67aca96f77428e316741082a1b", - "sha256:ef0fe7ad7cbdb5f372463d42e6ed4ca9c443a52ce544472d8842a0576d830da5", - "sha256:efbc8a7f9cb5fe26122acba1852d8dcd1e125e723727c59dcd244da7bdaa54f2", - "sha256:fcb20d4cb355195c75000a49bb4a31d75e4295200df620f454bbc6bdf60ca890", - "sha256:fe734914977eed33033b70bfc097e1baaffb589517863955430bf2e0846ac30f" + "sha256:0399094464ae7f28482de22383e667625e38e1516d6b213176df1acdd0c477ea", + "sha256:076c49e24b73d346c45f9282d00dbfc16eef7ae27c970583d499f11110d9e5b0", + "sha256:07d00ca5ef0de65dd274005433ce2bb623730271d495a7d190a91c19c5679d34", + "sha256:0890fbd7fec9e151c7512941243d830b2d6076d5df159a2030952d480ab80a4e", + "sha256:0bfb5b378b78229119d66ced6adac2e933c67a0aa1d0a7adffbe432f3ec14ce4", + "sha256:0d32227ea9a3bf537a2273fd2fdb6d64ab4d9b83acd9e4e09310a777baaabb98", + "sha256:11965f421f7eb026439d4eb7464e9182fe6d69c3d4d416e464a4485d1ba61ab6", + "sha256:1fc8cc264afaf47ae6a9bcbd36c018d0c6b89293835d7fb0e5e1a95898062d59", + "sha256:2206a1752d9fac011e95ca83926a269fb0ef5536f7e053966d058316e24d929f", + "sha256:22a1794e01591884741be56c6fba157c4e99dcc9244beb5a87bd4aa54b84ea8b", + "sha256:4739c206bfb6bb2bdc78dcd40bfcebb2361add4ceac6d170e741bb914e9eff0f", + "sha256:4a5d5b877c7d3d9e17399571a8ab042081d22fe6904416a8b20f8af5909e6c8f", + "sha256:566bebdbe6bc0ac593fa0f67d62febbad9f8be5433f686dc56401ba4aab034e3", + "sha256:570ad0aeaf98b5e33ff41af75aba2ef6604ee25ce0431ecd734a28e74a208555", + "sha256:573254d844f3e64093f72fcd922561d9c5696821ff0900a0db989d8c06ab0c25", + "sha256:5d4320510682d5a6c88766b2a286d03b87bd3562bf8d78c73d63bab04b21e7b4", + "sha256:6d8a38a44bb6a15810084316ed69c854a7c06e0c99c5429f1d664ad52cec353c", + "sha256:6eb56074b11a696e0b66c7181da682e88c00e5cebe6570af8013fcae5e63e186", + "sha256:7e66aa0fa7f8aa9d0a620361834f6eb60d01d3e9cea23ca1a92cda99e6f61dac", + "sha256:7ea24e8614f541d69ea72759ff635df0e612b7dc9d264d43f51364df310081a3", + "sha256:7f31742c95e3f9443b8c6fa07c119623e61d76603be9c0d390bcf7e888acabcb", + "sha256:83ee8c9916689f8e6e7d90161e6663ac876be2efd32f61fdcfa3a15e87d4e413", + "sha256:8b2cf5e26da84f2d2dee3f60a3f1782adedcee785567a19b68d0af7e1534bd1f", + "sha256:945407f4d08cd12485757a281fca0e5b41408606228612f421aa4ea1b63a095d", + "sha256:9c46f58ef2df958ed2ea7437a8be0897d5efe9ee480818405338c7da88186fb3", + "sha256:9d7d48fbc5289efd23982a0d68e973a1f37d49064ccd36d86de4543aff21e086", + "sha256:9f28a81978e936136c44e6a70c65bde7548d87f3807260f73aeffbf76fb94c2f", + "sha256:a415b9e95fa602b10808113967f72b2da8722061265d6af69268c111c254832d", + "sha256:a82746c6d6e91ca17e75f7f333ed41d70fce93af520a8437821dec3ee52dfb10", + "sha256:ad57004e5d73aee36f1e25e4e73a4bc853b473a1c30f652dc8d86b0a987ffce3", + "sha256:c6444368b651a14c2ce2fb22145e1496f7ab23cbdb978590d47c8d34a7bc0289", + "sha256:d216f8d0484d88ab72ab45d699ac669fe031275e3fa6553e3804e69485449fa0", + "sha256:d3449633c207ec3d2d672eedb3edbe753e29bd4e22d2e42a37a2c1406564c20f", + "sha256:d5b5b7c6bafaef90cbb7dafcb225b763edd71d9e22489647ee7df49d6d341890", + "sha256:d7a8a1dd68bac29f08f0a3147de1885f4dccec35d4ea926e6e637fac03cdb4b3", + "sha256:d8d72553d2f3f57ce547de4fa7dc8e3859927784ab2c88343f1fc1360ff17a08", + "sha256:dce355fe7ae53e3090f7f5fa242423c3a7b53260747aa398b4b3aaf8b25f41c3", + "sha256:e351df83d1c9cffa53d4e779009a093be70f1d5c6bb7068584086f6a19042526", + "sha256:ec5c44e6e9eac5128a9bfd21610df3b8c6b17343285cc185105686888dc81206", + "sha256:f5bb81fcfc6d5bff62cd786cbd87480a11d23f16d5376ad2e057c02b3b44df96", + "sha256:fd34012691fbd4e67bdf4accb1f0682342101015b78327eaae3543583fcd451e", + "sha256:fea36c2065b7a1d28c6819cc2e93387b43dd5d3cf5a1e82d8132ee23f36d1f10", + "sha256:ff09600cebe957ecbb4a27496fe34c1d449e7957ed20a202d5029a71a8af2e35" ], "markers": "python_version >= '3.7'", - "version": "==1.10.18" + "version": "==1.10.19" }, "pynacl": { "hashes": [ @@ -1242,11 +1250,11 @@ }, "setuptools": { "hashes": [ - "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec", - "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8" + "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd", + "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686" ], "markers": "python_version >= '3.8'", - "version": "==75.2.0" + "version": "==75.3.0" }, "six": { "hashes": [ @@ -1258,12 +1266,12 @@ }, "slack-sdk": { "hashes": [ - "sha256:e328bb661d95db5f66b993b1d64288ac7c72201a745b4c7cf8848dafb7b74e40", - "sha256:ef93beec3ce9c8f64da02fd487598a05ec4bc9c92ceed58f122dbe632691cbe2" + "sha256:0515fb93cd03b18de61f876a8304c4c3cef4dd3c2a3bad62d7394d2eb5a3c8e6", + "sha256:4cc44c9ffe4bb28a01fbe3264c2f466c783b893a4eca62026ab845ec7c176ff1" ], "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==3.33.1" + "version": "==3.33.3" }, "slackclient": { "hashes": [ @@ -1416,91 +1424,91 @@ }, "yarl": { "hashes": [ - "sha256:019f5d58093402aa8f6661e60fd82a28746ad6d156f6c5336a70a39bd7b162b9", - "sha256:0fd9c227990f609c165f56b46107d0bc34553fe0387818c42c02f77974402c36", - "sha256:1208ca14eed2fda324042adf8d6c0adf4a31522fa95e0929027cd487875f0240", - "sha256:122d8e7986043d0549e9eb23c7fd23be078be4b70c9eb42a20052b3d3149c6f2", - "sha256:147b0fcd0ee33b4b5f6edfea80452d80e419e51b9a3f7a96ce98eaee145c1581", - "sha256:178ccb856e265174a79f59721031060f885aca428983e75c06f78aa24b91d929", - "sha256:1a5cf32539373ff39d97723e39a9283a7277cbf1224f7aef0c56c9598b6486c3", - "sha256:1a5e9d8ce1185723419c487758d81ac2bde693711947032cce600ca7c9cda7d6", - "sha256:1bc22e00edeb068f71967ab99081e9406cd56dbed864fc3a8259442999d71552", - "sha256:1cf936ba67bc6c734f3aa1c01391da74ab7fc046a9f8bbfa230b8393b90cf472", - "sha256:234f3a3032b505b90e65b5bc6652c2329ea7ea8855d8de61e1642b74b4ee65d2", - "sha256:26768342f256e6e3c37533bf9433f5f15f3e59e3c14b2409098291b3efaceacb", - "sha256:27e11db3f1e6a51081a981509f75617b09810529de508a181319193d320bc5c7", - "sha256:2bd6a51010c7284d191b79d3b56e51a87d8e1c03b0902362945f15c3d50ed46b", - "sha256:2f1fe2b2e3ee418862f5ebc0c0083c97f6f6625781382f828f6d4e9b614eba9b", - "sha256:32468f41242d72b87ab793a86d92f885355bcf35b3355aa650bfa846a5c60058", - "sha256:35b4f7842154176523e0a63c9b871168c69b98065d05a4f637fce342a6a2693a", - "sha256:38fec8a2a94c58bd47c9a50a45d321ab2285ad133adefbbadf3012c054b7e656", - "sha256:3a91654adb7643cb21b46f04244c5a315a440dcad63213033826549fa2435f71", - "sha256:3ab3ed42c78275477ea8e917491365e9a9b69bb615cb46169020bd0aa5e2d6d3", - "sha256:3d375a19ba2bfe320b6d873f3fb165313b002cef8b7cc0a368ad8b8a57453837", - "sha256:4199db024b58a8abb2cfcedac7b1292c3ad421684571aeb622a02f242280e8d6", - "sha256:4f32c4cb7386b41936894685f6e093c8dfaf0960124d91fe0ec29fe439e201d0", - "sha256:4ffb7c129707dd76ced0a4a4128ff452cecf0b0e929f2668ea05a371d9e5c104", - "sha256:504e1fe1cc4f170195320eb033d2b0ccf5c6114ce5bf2f617535c01699479bca", - "sha256:542fa8e09a581bcdcbb30607c7224beff3fdfb598c798ccd28a8184ffc18b7eb", - "sha256:5570e6d47bcb03215baf4c9ad7bf7c013e56285d9d35013541f9ac2b372593e7", - "sha256:571f781ae8ac463ce30bacebfaef2c6581543776d5970b2372fbe31d7bf31a07", - "sha256:595ca5e943baed31d56b33b34736461a371c6ea0038d3baec399949dd628560b", - "sha256:5b8e265a0545637492a7e12fd7038370d66c9375a61d88c5567d0e044ded9202", - "sha256:5b9101f528ae0f8f65ac9d64dda2bb0627de8a50344b2f582779f32fda747c1d", - "sha256:5ff96da263740779b0893d02b718293cc03400c3a208fc8d8cd79d9b0993e532", - "sha256:621280719c4c5dad4c1391160a9b88925bb8b0ff6a7d5af3224643024871675f", - "sha256:62c7da0ad93a07da048b500514ca47b759459ec41924143e2ddb5d7e20fd3db5", - "sha256:649bddcedee692ee8a9b7b6e38582cb4062dc4253de9711568e5620d8707c2a3", - "sha256:66ea8311422a7ba1fc79b4c42c2baa10566469fe5a78500d4e7754d6e6db8724", - "sha256:676d96bafc8c2d0039cea0cd3fd44cee7aa88b8185551a2bb93354668e8315c2", - "sha256:707ae579ccb3262dfaef093e202b4c3fb23c3810e8df544b1111bd2401fd7b09", - "sha256:7118bdb5e3ed81acaa2095cba7ec02a0fe74b52a16ab9f9ac8e28e53ee299732", - "sha256:789a3423f28a5fff46fbd04e339863c169ece97c827b44de16e1a7a42bc915d2", - "sha256:7ace71c4b7a0c41f317ae24be62bb61e9d80838d38acb20e70697c625e71f120", - "sha256:7c7c30fb38c300fe8140df30a046a01769105e4cf4282567a29b5cdb635b66c4", - "sha256:7d7aaa8ff95d0840e289423e7dc35696c2b058d635f945bf05b5cd633146b027", - "sha256:7f8713717a09acbfee7c47bfc5777e685539fefdd34fa72faf504c8be2f3df4e", - "sha256:858728086914f3a407aa7979cab743bbda1fe2bdf39ffcd991469a370dd7414d", - "sha256:8791d66d81ee45866a7bb15a517b01a2bcf583a18ebf5d72a84e6064c417e64b", - "sha256:87dd10bc0618991c66cee0cc65fa74a45f4ecb13bceec3c62d78ad2e42b27a16", - "sha256:8994c42f4ca25df5380ddf59f315c518c81df6a68fed5bb0c159c6cb6b92f120", - "sha256:8a0296040e5cddf074c7f5af4a60f3fc42c0237440df7bcf5183be5f6c802ed5", - "sha256:8b37d5ec034e668b22cf0ce1074d6c21fd2a08b90d11b1b73139b750a8b0dd97", - "sha256:8c42998fd1cbeb53cd985bff0e4bc25fbe55fd6eb3a545a724c1012d69d5ec84", - "sha256:8f639e3f5795a6568aa4f7d2ac6057c757dcd187593679f035adbf12b892bb00", - "sha256:921b81b8d78f0e60242fb3db615ea3f368827a76af095d5a69f1c3366db3f596", - "sha256:995d0759004c08abd5d1b81300a91d18c8577c6389300bed1c7c11675105a44d", - "sha256:99a9dcd4b71dd5f5f949737ab3f356cfc058c709b4f49833aeffedc2652dac56", - "sha256:9a91217208306d82357c67daeef5162a41a28c8352dab7e16daa82e3718852a7", - "sha256:a5ace0177520bd4caa99295a9b6fb831d0e9a57d8e0501a22ffaa61b4c024283", - "sha256:a5b6c09b9b4253d6a208b0f4a2f9206e511ec68dce9198e0fbec4f160137aa67", - "sha256:a9394c65ae0ed95679717d391c862dece9afacd8fa311683fc8b4362ce8a410c", - "sha256:aa7943f04f36d6cafc0cf53ea89824ac2c37acbdb4b316a654176ab8ffd0f968", - "sha256:ab2b2ac232110a1fdb0d3ffcd087783edd3d4a6ced432a1bf75caf7b7be70916", - "sha256:ad7a852d1cd0b8d8b37fc9d7f8581152add917a98cfe2ea6e241878795f917ae", - "sha256:b140e532fe0266003c936d017c1ac301e72ee4a3fd51784574c05f53718a55d8", - "sha256:b439cae82034ade094526a8f692b9a2b5ee936452de5e4c5f0f6c48df23f8604", - "sha256:b6f687ced5510a9a2474bbae96a4352e5ace5fa34dc44a217b0537fec1db00b4", - "sha256:b9ca7b9147eb1365c8bab03c003baa1300599575effad765e0b07dd3501ea9af", - "sha256:bdcf667a5dec12a48f669e485d70c54189f0639c2157b538a4cffd24a853624f", - "sha256:cdcffe1dbcb4477d2b4202f63cd972d5baa155ff5a3d9e35801c46a415b7f71a", - "sha256:d1aab176dd55b59f77a63b27cffaca67d29987d91a5b615cbead41331e6b7428", - "sha256:d1b0796168b953bca6600c5f97f5ed407479889a36ad7d17183366260f29a6b9", - "sha256:d3f1cc3d3d4dc574bebc9b387f6875e228ace5748a7c24f49d8f01ac1bc6c31b", - "sha256:d743e3118b2640cef7768ea955378c3536482d95550222f908f392167fe62059", - "sha256:d8643975a0080f361639787415a038bfc32d29208a4bf6b783ab3075a20b1ef3", - "sha256:d9525f03269e64310416dbe6c68d3b23e5d34aaa8f47193a1c45ac568cecbc49", - "sha256:de6c14dd7c7c0badba48157474ea1f03ebee991530ba742d381b28d4f314d6f3", - "sha256:e49e0fd86c295e743fd5be69b8b0712f70a686bc79a16e5268386c2defacaade", - "sha256:e6980a558d8461230c457218bd6c92dfc1d10205548215c2c21d79dc8d0a96f3", - "sha256:e8be3aff14f0120ad049121322b107f8a759be76a6a62138322d4c8a337a9e2c", - "sha256:e9951afe6557c75a71045148890052cb942689ee4c9ec29f5436240e1fcc73b7", - "sha256:ed097b26f18a1f5ff05f661dc36528c5f6735ba4ce8c9645e83b064665131349", - "sha256:f1d1f45e3e8d37c804dca99ab3cf4ab3ed2e7a62cd82542924b14c0a4f46d243", - "sha256:fe8bba2545427418efc1929c5c42852bdb4143eb8d0a46b09de88d1fe99258e7" + "sha256:06157fb3c58f2736a5e47c8fcbe1afc8b5de6fb28b14d25574af9e62150fcaac", + "sha256:067a63fcfda82da6b198fa73079b1ca40b7c9b7994995b6ee38acda728b64d47", + "sha256:0b1794853124e2f663f0ea54efb0340b457f08d40a1cef78edfa086576179c91", + "sha256:0bdff5e0995522706c53078f531fb586f56de9c4c81c243865dd5c66c132c3b5", + "sha256:117ed8b3732528a1e41af3aa6d4e08483c2f0f2e3d3d7dca7cf538b3516d93df", + "sha256:14bc88baa44e1f84164a392827b5defb4fa8e56b93fecac3d15315e7c8e5d8b3", + "sha256:1654ec814b18be1af2c857aa9000de7a601400bd4c9ca24629b18486c2e35463", + "sha256:16bca6678a83657dd48df84b51bd56a6c6bd401853aef6d09dc2506a78484c7b", + "sha256:1a3b91c44efa29e6c8ef8a9a2b583347998e2ba52c5d8280dbd5919c02dfc3b5", + "sha256:1a52a1ffdd824fb1835272e125385c32fd8b17fbdefeedcb4d543cc23b332d74", + "sha256:1ce36ded585f45b1e9bb36d0ae94765c6608b43bd2e7f5f88079f7a85c61a4d3", + "sha256:299f11b44d8d3a588234adbe01112126010bd96d9139c3ba7b3badd9829261c3", + "sha256:2b24ec55fad43e476905eceaf14f41f6478780b870eda5d08b4d6de9a60b65b4", + "sha256:2d374d70fdc36f5863b84e54775452f68639bc862918602d028f89310a034ab0", + "sha256:2d9f0606baaec5dd54cb99667fcf85183a7477f3766fbddbe3f385e7fc253299", + "sha256:2e7ba4c9377e48fb7b20dedbd473cbcbc13e72e1826917c185157a137dac9df2", + "sha256:2f0a6423295a0d282d00e8701fe763eeefba8037e984ad5de44aa349002562ac", + "sha256:327828786da2006085a4d1feb2594de6f6d26f8af48b81eb1ae950c788d97f61", + "sha256:380e6c38ef692b8fd5a0f6d1fa8774d81ebc08cfbd624b1bca62a4d4af2f9931", + "sha256:3b74ff4767d3ef47ffe0cd1d89379dc4d828d4873e5528976ced3b44fe5b0a21", + "sha256:3e844be8d536afa129366d9af76ed7cb8dfefec99f5f1c9e4f8ae542279a6dc3", + "sha256:459e81c2fb920b5f5df744262d1498ec2c8081acdcfe18181da44c50f51312f7", + "sha256:46ddf6e0b975cd680eb83318aa1d321cb2bf8d288d50f1754526230fcf59ba96", + "sha256:482c122b72e3c5ec98f11457aeb436ae4aecca75de19b3d1de7cf88bc40db82f", + "sha256:561c87fea99545ef7d692403c110b2f99dced6dff93056d6e04384ad3bc46243", + "sha256:578d00c9b7fccfa1745a44f4eddfdc99d723d157dad26764538fbdda37209857", + "sha256:58c8e9620eb82a189c6c40cb6b59b4e35b2ee68b1f2afa6597732a2b467d7e8f", + "sha256:5b29beab10211a746f9846baa39275e80034e065460d99eb51e45c9a9495bcca", + "sha256:5d1d42556b063d579cae59e37a38c61f4402b47d70c29f0ef15cee1acaa64488", + "sha256:5f236cb5999ccd23a0ab1bd219cfe0ee3e1c1b65aaf6dd3320e972f7ec3a39da", + "sha256:62a91aefff3d11bf60e5956d340eb507a983a7ec802b19072bb989ce120cd948", + "sha256:64cc6e97f14cf8a275d79c5002281f3040c12e2e4220623b5759ea7f9868d6a5", + "sha256:6f4c9156c4d1eb490fe374fb294deeb7bc7eaccda50e23775b2354b6a6739934", + "sha256:7294e38f9aa2e9f05f765b28ffdc5d81378508ce6dadbe93f6d464a8c9594473", + "sha256:7615058aabad54416ddac99ade09a5510cf77039a3b903e94e8922f25ed203d7", + "sha256:7e48cdb8226644e2fbd0bdb0a0f87906a3db07087f4de77a1b1b1ccfd9e93685", + "sha256:7f63d176a81555984e91f2c84c2a574a61cab7111cc907e176f0f01538e9ff6e", + "sha256:7f6595c852ca544aaeeb32d357e62c9c780eac69dcd34e40cae7b55bc4fb1147", + "sha256:7fac95714b09da9278a0b52e492466f773cfe37651cf467a83a1b659be24bf71", + "sha256:81713b70bea5c1386dc2f32a8f0dab4148a2928c7495c808c541ee0aae614d67", + "sha256:846dd2e1243407133d3195d2d7e4ceefcaa5f5bf7278f0a9bda00967e6326b04", + "sha256:84c063af19ef5130084db70ada40ce63a84f6c1ef4d3dbc34e5e8c4febb20822", + "sha256:881764d610e3269964fc4bb3c19bb6fce55422828e152b885609ec176b41cf11", + "sha256:8994b29c462de9a8fce2d591028b986dbbe1b32f3ad600b2d3e1c482c93abad6", + "sha256:8c79e9d7e3d8a32d4824250a9c6401194fb4c2ad9a0cec8f6a96e09a582c2cc0", + "sha256:8ee427208c675f1b6e344a1f89376a9613fc30b52646a04ac0c1f6587c7e46ec", + "sha256:949681f68e0e3c25377462be4b658500e85ca24323d9619fdc41f68d46a1ffda", + "sha256:9e275792097c9f7e80741c36de3b61917aebecc08a67ae62899b074566ff8556", + "sha256:9fb815155aac6bfa8d86184079652c9715c812d506b22cfa369196ef4e99d1b4", + "sha256:a2a64e62c7a0edd07c1c917b0586655f3362d2c2d37d474db1a509efb96fea1c", + "sha256:a7ac5b4984c468ce4f4a553df281450df0a34aefae02e58d77a0847be8d1e11f", + "sha256:aa46dce75078fceaf7cecac5817422febb4355fbdda440db55206e3bd288cfb8", + "sha256:ae3476e934b9d714aa8000d2e4c01eb2590eee10b9d8cd03e7983ad65dfbfcba", + "sha256:b0341e6d9a0c0e3cdc65857ef518bb05b410dbd70d749a0d33ac0f39e81a4258", + "sha256:b40d1bf6e6f74f7c0a567a9e5e778bbd4699d1d3d2c0fe46f4b717eef9e96b95", + "sha256:b5c4804e4039f487e942c13381e6c27b4b4e66066d94ef1fae3f6ba8b953f383", + "sha256:b5d6a6c9602fd4598fa07e0389e19fe199ae96449008d8304bf5d47cb745462e", + "sha256:b5f1ac7359e17efe0b6e5fec21de34145caef22b260e978336f325d5c84e6938", + "sha256:c0167540094838ee9093ef6cc2c69d0074bbf84a432b4995835e8e5a0d984374", + "sha256:c180ac742a083e109c1a18151f4dd8675f32679985a1c750d2ff806796165b55", + "sha256:c73df5b6e8fabe2ddb74876fb82d9dd44cbace0ca12e8861ce9155ad3c886139", + "sha256:c7e177c619342e407415d4f35dec63d2d134d951e24b5166afcdfd1362828e17", + "sha256:cbad927ea8ed814622305d842c93412cb47bd39a496ed0f96bfd42b922b4a217", + "sha256:cc353841428d56b683a123a813e6a686e07026d6b1c5757970a877195f880c2d", + "sha256:cc7c92c1baa629cb03ecb0c3d12564f172218fb1739f54bf5f3881844daadc6d", + "sha256:cc7d768260f4ba4ea01741c1b5fe3d3a6c70eb91c87f4c8761bbcce5181beafe", + "sha256:d0eea830b591dbc68e030c86a9569826145df485b2b4554874b07fea1275a199", + "sha256:d216e5d9b8749563c7f2c6f7a0831057ec844c68b4c11cb10fc62d4fd373c26d", + "sha256:d401f07261dc5aa36c2e4efc308548f6ae943bfff20fcadb0a07517a26b196d8", + "sha256:d6324274b4e0e2fa1b3eccb25997b1c9ed134ff61d296448ab8269f5ac068c4c", + "sha256:d8a8b74d843c2638f3864a17d97a4acda58e40d3e44b6303b8cc3d3c44ae2d29", + "sha256:d9b6b28a57feb51605d6ae5e61a9044a31742db557a3b851a74c13bc61de5172", + "sha256:de599af166970d6a61accde358ec9ded821234cbbc8c6413acfec06056b8e860", + "sha256:e594b22688d5747b06e957f1ef822060cb5cb35b493066e33ceac0cf882188b7", + "sha256:e5b078134f48552c4d9527db2f7da0b5359abd49393cdf9794017baec7506170", + "sha256:eb6dce402734575e1a8cc0bb1509afca508a400a57ce13d306ea2c663bad1138", + "sha256:f1790a4b1e8e8e028c391175433b9c8122c39b46e1663228158e61e6f915bf06", + "sha256:f5efe0661b9fcd6246f27957f6ae1c0eb29bc60552820f01e970b4996e016004", + "sha256:f9cbfbc5faca235fbdf531b93aa0f9f005ec7d267d9d738761a4d42b744ea159", + "sha256:fbea1751729afe607d84acfd01efd95e3b31db148a181a441984ce9b3d3469da", + "sha256:fca4b4307ebe9c3ec77a084da3a9d1999d164693d16492ca2b64594340999988", + "sha256:ff5c6771c7e3511a06555afa317879b7db8d640137ba55d6ab0d0c50425cab75" ], "markers": "python_version >= '3.9'", - "version": "==1.16.0" + "version": "==1.17.1" } }, "develop": { @@ -1797,20 +1805,20 @@ }, "google-api-core": { "hashes": [ - "sha256:4a152fd11a9f774ea606388d423b68aa7e6d6a0ffe4c8266f74979613ec09f81", - "sha256:6869eacb2a37720380ba5898312af79a4d30b8bca1548fb4093e0697dc4bdf5d" + "sha256:26f8d76b96477db42b55fd02a33aae4a42ec8b86b98b94969b7333a2c828bf35", + "sha256:a6652b6bd51303902494998626653671703c420f6f4c88cfd3f50ed723e9d021" ], "markers": "python_version >= '3.7'", - "version": "==2.21.0" + "version": "==2.22.0" }, "google-api-python-client": { "hashes": [ - "sha256:1a5232e9cfed8c201799d9327e4d44dc7ea7daa3c6e1627fca41aa201539c0da", - "sha256:b9d68c6b14ec72580d66001bd33c5816b78e2134b93ccc5cf8f624516b561750" + "sha256:4427b2f47cd88b0355d540c2c52215f68c337f3bc9d6aae1ceeae4525977504c", + "sha256:a9d26d630810ed4631aea21d1de3e42072f98240aaf184a8a1a874a371115034" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==2.149.0" + "version": "==2.151.0" }, "google-api-python-client-stubs": { "hashes": [ @@ -1823,11 +1831,11 @@ }, "google-auth": { "hashes": [ - "sha256:25df55f327ef021de8be50bad0dfd4a916ad0de96da86cd05661c9297723ad3f", - "sha256:f4c64ed4e01e8e8b646ef34c018f8bf3338df0c8e37d8b3bba40e7f574a3278a" + "sha256:51a15d47028b66fd36e5c64a82d2d57480075bccc7da37cde257fc94177a61fb", + "sha256:545e9618f2df0bcbb7dcbc45a546485b1212624716975a1ea5ae8149ce769ab1" ], "markers": "python_version >= '3.7'", - "version": "==2.35.0" + "version": "==2.36.0" }, "google-auth-httplib2": { "hashes": [ @@ -1952,11 +1960,11 @@ }, "proto-plus": { "hashes": [ - "sha256:30b72a5ecafe4406b0d339db35b56c4059064e69227b8c3bda7462397f966445", - "sha256:402576830425e5f6ce4c2a6702400ac79897dab0b4343821aa5188b0fab81a12" + "sha256:c91fc4a65074ade8e458e95ef8bac34d4008daa7cce4a12d6707066fca648961", + "sha256:fbb17f57f7bd05a68b7707e745e26528b0b3c34e378db91eef93912c54982d91" ], "markers": "python_version >= '3.7'", - "version": "==1.24.0" + "version": "==1.25.0" }, "protobuf": { "hashes": [ diff --git a/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json b/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json index 600f030583f..3b56adf18bc 100644 --- a/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json +++ b/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json @@ -1124,4 +1124,4 @@ "y": 0, "z": 0 } -} \ No newline at end of file +} From 709ad31e7ffd3b5d364ea31bac1f22f35c0bddec Mon Sep 17 00:00:00 2001 From: rclarke0 Date: Thu, 7 Nov 2024 16:39:58 -0500 Subject: [PATCH 09/13] add line on json --- .../protocols/custom_labware/hellma_reference_plate.json | 1 + 1 file changed, 1 insertion(+) diff --git a/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json b/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json index 3b56adf18bc..969d6086699 100644 --- a/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json +++ b/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json @@ -1125,3 +1125,4 @@ "z": 0 } } + From 14b01676364d95916a796025268ad6821181fc31 Mon Sep 17 00:00:00 2001 From: Seth Foster Date: Fri, 8 Nov 2024 09:20:24 -0500 Subject: [PATCH 10/13] ignore abr aprotocols in formatting --- .eslintignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.eslintignore b/.eslintignore index 1eb52b86b10..5d9406d522a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -28,6 +28,9 @@ robot-server/** shared-data/python/** hardware-testing/** +# abr-testing don't format the json protocols +abr-testing/protocols/** + # analyses-snapshot-testing don't format the json protocols analyses-snapshot-testing/files # don't format the snapshots From d7ea4a99276b9334fa8fd2ba932e7de7e096b4fc Mon Sep 17 00:00:00 2001 From: rclarke0 Date: Fri, 8 Nov 2024 10:08:20 -0500 Subject: [PATCH 11/13] changed volumes to float --- .../10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py | 14 +- .../11_Dynabeads_IP_Flex_96well_RIT.py | 10 +- .../12_KAPA HyperPlus Library Prep.py | 45 +- .../7_HDQ_DNA_Bacteria_Flex.py | 14 +- .../hellma_reference_plate.json | 2139 ++++++++--------- abr-testing/abr_testing/protocols/helpers.py | 2 +- ...ermo MagMax RNA Extraction Liquid Setup.py | 14 +- 7 files changed, 1065 insertions(+), 1173 deletions(-) diff --git a/abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py b/abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py index e193869179d..62a077cbc5f 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py +++ b/abr-testing/abr_testing/protocols/active_protocols/10_ZymoBIOMICS_Magbead_DNA_Cells_Flex.py @@ -67,13 +67,13 @@ def run(ctx: protocol_api.ProtocolContext) -> None: res_type = "nest_12_reservoir_15ml" num_samples = 8 - wash1_vol = 500 - wash2_vol = wash3_vol = 900 - lysis_vol = 200 - sample_vol = 10 # Sample should be pelleted tissue/bacteria/cells - bind_vol = 600 - bind2_vol = 500 - elution_vol = 75 + wash1_vol = 500.0 + wash2_vol = wash3_vol = 900.0 + lysis_vol = 200.0 + sample_vol = 10.0 # Sample should be pelleted tissue/bacteria/cells + bind_vol = 600.0 + bind2_vol = 500.0 + elution_vol = 75.0 # Protocol Parameters deepwell_type = "nest_96_wellplate_2ml_deep" diff --git a/abr-testing/abr_testing/protocols/active_protocols/11_Dynabeads_IP_Flex_96well_RIT.py b/abr-testing/abr_testing/protocols/active_protocols/11_Dynabeads_IP_Flex_96well_RIT.py index dec881f9199..a50e0b94904 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/11_Dynabeads_IP_Flex_96well_RIT.py +++ b/abr-testing/abr_testing/protocols/active_protocols/11_Dynabeads_IP_Flex_96well_RIT.py @@ -119,11 +119,11 @@ def run(ctx: ProtocolContext) -> None: liquid_vols_and_wells: Dict[ str, List[Dict[str, Union[Well, List[Well], float]]] ] = { - "Beads": [{"well": beads, "volume": 4900}], - "AB": [{"well": ab, "volume": 4900}], - "Elution": [{"well": elu, "volume": 4900}], - "Wash": [{"well": wash, "volume": 750}], - "Samples": [{"well": samples, "volume": 250}], + "Beads": [{"well": beads, "volume": 4900.0}], + "AB": [{"well": ab, "volume": 4900.0}], + "Elution": [{"well": elu, "volume": 4900.0}], + "Wash": [{"well": wash, "volume": 750.0}], + "Samples": [{"well": samples, "volume": 250.0}], } flattened_wells = helpers.find_liquid_height_of_loaded_liquids( ctx, liquid_vols_and_wells, p1000_single diff --git a/abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py b/abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py index 3488e898dd9..03fd2d9769c 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py +++ b/abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py @@ -85,11 +85,11 @@ def run(ctx: ProtocolContext) -> None: dry_run = ctx.params.dry_run # type: ignore[attr-defined] pipette_1000_mount = ctx.params.pipette_mount_1 # type: ignore[attr-defined] pipette_50_mount = ctx.params.pipette_mount_2 # type: ignore[attr-defined] - REUSE_ETOH_TIPS = False + REUSE_ETOH_TIPS = True REUSE_RSB_TIPS = ( - False # Reuse tips for RSB buffer (adding RSB, mixing, and transferring) + True # Reuse tips for RSB buffer (adding RSB, mixing, and transferring) ) - REUSE_REMOVE_TIPS = False # Reuse tips for supernatant removal + REUSE_REMOVE_TIPS = True # Reuse tips for supernatant removal num_samples = ctx.params.num_samples # type: ignore[attr-defined] PCRCYCLES = ctx.params.PCR_CYCLES # type: ignore[attr-defined] disposable_lid = ctx.params.disposable_lid # type: ignore[attr-defined] @@ -102,22 +102,22 @@ def run(ctx: ProtocolContext) -> None: num_cols = math.ceil(num_samples / 8) # Pre-set parameters - sample_vol = 35 - frag_vol = 15 - end_repair_vol = 10 - adapter_vol = 5 - ligation_vol = 45 - amplification_vol = 30 - bead_vol_1 = 88 - bead_vol_2 = 50 + sample_vol = 35.0 + frag_vol = 15.0 + end_repair_vol = 10.0 + adapter_vol = 5.0 + ligation_vol = 45.0 + amplification_vol = 30.0 + bead_vol_1 = 88.0 + bead_vol_2 = 50.0 bead_vol = bead_vol_1 + bead_vol_2 - bead_inc = 2 - rsb_vol_1 = 25 - rsb_vol_2 = 20 + bead_inc = 2.0 + rsb_vol_1 = 25.0 + rsb_vol_2 = 20.0 rsb_vol = rsb_vol_1 + rsb_vol_2 - elution_vol = 20 - elution_vol_2 = 17 - etoh_vol = 400 + elution_vol = 20.0 + elution_vol_2 = 17.0 + etoh_vol = 400.0 # Importing Labware, Modules and Instruments magblock: MagneticBlockContext = ctx.load_module( @@ -139,24 +139,27 @@ def run(ctx: ProtocolContext) -> None: tc_mod.open_lid() FLP_plate = magblock.load_labware( - "opentrons_96_wellplate_200ul_pcr_full_skirt", "FLP Plate" + "armadillo_96_wellplate_200ul_pcr_full_skirt", "FLP Plate" ) samples_flp = FLP_plate.rows()[0][:num_cols] sample_plate = ctx.load_labware( - "opentrons_96_wellplate_200ul_pcr_full_skirt", "D1", "Sample Pate" + "armadillo_96_wellplate_200ul_pcr_full_skirt", "D1", "Sample Pate" ) sample_plate_2 = ctx.load_labware( - "opentrons_96_wellplate_200ul_pcr_full_skirt", "B2", "Sample Pate" + "armadillo_96_wellplate_200ul_pcr_full_skirt", "B2", "Sample Pate" ) samples_2 = sample_plate_2.rows()[0][:num_cols] samples = sample_plate.rows()[0][:num_cols] reservoir = ctx.load_labware("nest_96_wellplate_2ml_deep", "C2") trash = ctx.load_waste_chute() + unused_lids: List[Labware] = [] + used_lids:List[Labware] = [] # Load TC Lids - unused_lids = helpers.load_disposable_lids(ctx, 5, ["C3"]) + if disposable_lid: + unused_lids = helpers.load_disposable_lids(ctx, 5, ["C3"]) # Import Global Variables global tip50 diff --git a/abr-testing/abr_testing/protocols/active_protocols/7_HDQ_DNA_Bacteria_Flex.py b/abr-testing/abr_testing/protocols/active_protocols/7_HDQ_DNA_Bacteria_Flex.py index a11f4f94ed9..f247af69c5f 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/7_HDQ_DNA_Bacteria_Flex.py +++ b/abr-testing/abr_testing/protocols/active_protocols/7_HDQ_DNA_Bacteria_Flex.py @@ -69,13 +69,13 @@ def run(ctx: ProtocolContext) -> None: res_type = "nest_12_reservoir_22ml" num_samples = 8 - wash1_vol = 600 - wash2_vol = 600 - wash3_vol = 600 - AL_vol = 230 - sample_vol = 180 - bind_vol = 320 - elution_vol = 100 + wash1_vol = 600.0 + wash2_vol = 600.0 + wash3_vol = 600.0 + AL_vol = 230.0 + sample_vol = 180.0 + bind_vol = 320.0 + elution_vol = 100.0 # Protocol Parameters deepwell_type = "nest_96_wellplate_2ml_deep" diff --git a/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json b/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json index 969d6086699..0abef3ca15f 100644 --- a/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json +++ b/abr-testing/abr_testing/protocols/custom_labware/hellma_reference_plate.json @@ -1,1128 +1,1017 @@ { - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1" - ], - [ - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2" - ], - [ - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3" - ], - [ - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4" - ], - [ - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5" - ], - [ - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6" - ], - [ - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7" - ], - [ - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8" - ], - [ - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9" - ], - [ - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10" - ], - [ - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11" - ], - [ - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ] - ], - "brand": { - "brand": "Hellma", - "brandId": [ - "666-R013 Reference Plate" - ] - }, - "metadata": { - "displayName": "Hellma Reference Plate", - "displayCategory": "wellPlate", - "displayVolumeUnits": "µL", - "tags": [] - }, - "dimensions": { - "xDimension": 127, - "yDimension": 85.5, - "zDimension": 13 - }, - "wells": { - "A1": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 14.38, - "y": 74.26, - "z": 12 - }, - "B1": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 14.38, - "y": 65.26, - "z": 12 - }, - "C1": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 14.38, - "y": 56.26, - "z": 12 - }, - "D1": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 14.38, - "y": 47.26, - "z": 12 - }, - "E1": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 14.38, - "y": 38.26, - "z": 12 - }, - "F1": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 14.38, - "y": 29.26, - "z": 12 - }, - "G1": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 14.38, - "y": 20.26, - "z": 12 - }, - "H1": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 14.38, - "y": 11.26, - "z": 12 - }, - "A2": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 23.38, - "y": 74.26, - "z": 12 - }, - "B2": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 23.38, - "y": 65.26, - "z": 12 - }, - "C2": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 23.38, - "y": 56.26, - "z": 12 - }, - "D2": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 23.38, - "y": 47.26, - "z": 12 - }, - "E2": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 23.38, - "y": 38.26, - "z": 12 - }, - "F2": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 23.38, - "y": 29.26, - "z": 12 - }, - "G2": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 23.38, - "y": 20.26, - "z": 12 - }, - "H2": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 23.38, - "y": 11.26, - "z": 12 - }, - "A3": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 32.38, - "y": 74.26, - "z": 12 - }, - "B3": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 32.38, - "y": 65.26, - "z": 12 - }, - "C3": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 32.38, - "y": 56.26, - "z": 12 - }, - "D3": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 32.38, - "y": 47.26, - "z": 12 - }, - "E3": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 32.38, - "y": 38.26, - "z": 12 - }, - "F3": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 32.38, - "y": 29.26, - "z": 12 - }, - "G3": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 32.38, - "y": 20.26, - "z": 12 - }, - "H3": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 32.38, - "y": 11.26, - "z": 12 - }, - "A4": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 41.38, - "y": 74.26, - "z": 12 - }, - "B4": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 41.38, - "y": 65.26, - "z": 12 - }, - "C4": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 41.38, - "y": 56.26, - "z": 12 - }, - "D4": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 41.38, - "y": 47.26, - "z": 12 - }, - "E4": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 41.38, - "y": 38.26, - "z": 12 - }, - "F4": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 41.38, - "y": 29.26, - "z": 12 - }, - "G4": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 41.38, - "y": 20.26, - "z": 12 - }, - "H4": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 41.38, - "y": 11.26, - "z": 12 - }, - "A5": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 50.38, - "y": 74.26, - "z": 12 - }, - "B5": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 50.38, - "y": 65.26, - "z": 12 - }, - "C5": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 50.38, - "y": 56.26, - "z": 12 - }, - "D5": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 50.38, - "y": 47.26, - "z": 12 - }, - "E5": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 50.38, - "y": 38.26, - "z": 12 - }, - "F5": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 50.38, - "y": 29.26, - "z": 12 - }, - "G5": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 50.38, - "y": 20.26, - "z": 12 - }, - "H5": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 50.38, - "y": 11.26, - "z": 12 - }, - "A6": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 59.38, - "y": 74.26, - "z": 12 - }, - "B6": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 59.38, - "y": 65.26, - "z": 12 - }, - "C6": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 59.38, - "y": 56.26, - "z": 12 - }, - "D6": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 59.38, - "y": 47.26, - "z": 12 - }, - "E6": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 59.38, - "y": 38.26, - "z": 12 - }, - "F6": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 59.38, - "y": 29.26, - "z": 12 - }, - "G6": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 59.38, - "y": 20.26, - "z": 12 - }, - "H6": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 59.38, - "y": 11.26, - "z": 12 - }, - "A7": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 68.38, - "y": 74.26, - "z": 12 - }, - "B7": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 68.38, - "y": 65.26, - "z": 12 - }, - "C7": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 68.38, - "y": 56.26, - "z": 12 - }, - "D7": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 68.38, - "y": 47.26, - "z": 12 - }, - "E7": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 68.38, - "y": 38.26, - "z": 12 - }, - "F7": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 68.38, - "y": 29.26, - "z": 12 - }, - "G7": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 68.38, - "y": 20.26, - "z": 12 - }, - "H7": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 68.38, - "y": 11.26, - "z": 12 - }, - "A8": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 77.38, - "y": 74.26, - "z": 12 - }, - "B8": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 77.38, - "y": 65.26, - "z": 12 - }, - "C8": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 77.38, - "y": 56.26, - "z": 12 - }, - "D8": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 77.38, - "y": 47.26, - "z": 12 - }, - "E8": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 77.38, - "y": 38.26, - "z": 12 - }, - "F8": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 77.38, - "y": 29.26, - "z": 12 - }, - "G8": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 77.38, - "y": 20.26, - "z": 12 - }, - "H8": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 77.38, - "y": 11.26, - "z": 12 - }, - "A9": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 86.38, - "y": 74.26, - "z": 12 - }, - "B9": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 86.38, - "y": 65.26, - "z": 12 - }, - "C9": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 86.38, - "y": 56.26, - "z": 12 - }, - "D9": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 86.38, - "y": 47.26, - "z": 12 - }, - "E9": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 86.38, - "y": 38.26, - "z": 12 - }, - "F9": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 86.38, - "y": 29.26, - "z": 12 - }, - "G9": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 86.38, - "y": 20.26, - "z": 12 - }, - "H9": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 86.38, - "y": 11.26, - "z": 12 - }, - "A10": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 95.38, - "y": 74.26, - "z": 12 - }, - "B10": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 95.38, - "y": 65.26, - "z": 12 - }, - "C10": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 95.38, - "y": 56.26, - "z": 12 - }, - "D10": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 95.38, - "y": 47.26, - "z": 12 - }, - "E10": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 95.38, - "y": 38.26, - "z": 12 - }, - "F10": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 95.38, - "y": 29.26, - "z": 12 - }, - "G10": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 95.38, - "y": 20.26, - "z": 12 - }, - "H10": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 95.38, - "y": 11.26, - "z": 12 - }, - "A11": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 104.38, - "y": 74.26, - "z": 12 - }, - "B11": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 104.38, - "y": 65.26, - "z": 12 - }, - "C11": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 104.38, - "y": 56.26, - "z": 12 - }, - "D11": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 104.38, - "y": 47.26, - "z": 12 - }, - "E11": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 104.38, - "y": 38.26, - "z": 12 - }, - "F11": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 104.38, - "y": 29.26, - "z": 12 - }, - "G11": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 104.38, - "y": 20.26, - "z": 12 - }, - "H11": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 104.38, - "y": 11.26, - "z": 12 - }, - "A12": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 113.38, - "y": 74.26, - "z": 12 - }, - "B12": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 113.38, - "y": 65.26, - "z": 12 - }, - "C12": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 113.38, - "y": 56.26, - "z": 12 - }, - "D12": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 113.38, - "y": 47.26, - "z": 12 - }, - "E12": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 113.38, - "y": 38.26, - "z": 12 - }, - "F12": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 113.38, - "y": 29.26, - "z": 12 - }, - "G12": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 113.38, - "y": 20.26, - "z": 12 - }, - "H12": { - "depth": 1, - "totalLiquidVolume": 1, - "shape": "circular", - "diameter": 6.6, - "x": 113.38, - "y": 11.26, - "z": 12 - } - }, - "groups": [ - { - "metadata": { - "wellBottomShape": "flat" - }, - "wells": [ - "A1", - "B1", - "C1", - "D1", - "E1", - "F1", - "G1", - "H1", - "A2", - "B2", - "C2", - "D2", - "E2", - "F2", - "G2", - "H2", - "A3", - "B3", - "C3", - "D3", - "E3", - "F3", - "G3", - "H3", - "A4", - "B4", - "C4", - "D4", - "E4", - "F4", - "G4", - "H4", - "A5", - "B5", - "C5", - "D5", - "E5", - "F5", - "G5", - "H5", - "A6", - "B6", - "C6", - "D6", - "E6", - "F6", - "G6", - "H6", - "A7", - "B7", - "C7", - "D7", - "E7", - "F7", - "G7", - "H7", - "A8", - "B8", - "C8", - "D8", - "E8", - "F8", - "G8", - "H8", - "A9", - "B9", - "C9", - "D9", - "E9", - "F9", - "G9", - "H9", - "A10", - "B10", - "C10", - "D10", - "E10", - "F10", - "G10", - "H10", - "A11", - "B11", - "C11", - "D11", - "E11", - "F11", - "G11", - "H11", - "A12", - "B12", - "C12", - "D12", - "E12", - "F12", - "G12", - "H12" - ] - } - ], - "parameters": { - "format": "irregular", - "quirks": [], - "isTiprack": false, - "isMagneticModuleCompatible": false, - "loadName": "hellma_reference_plate" - }, - "namespace": "custom_beta", - "version": 1, - "schemaVersion": 2, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 + "ordering": [ + ["A1", "B1", "C1", "D1", "E1", "F1", "G1", "H1"], + ["A2", "B2", "C2", "D2", "E2", "F2", "G2", "H2"], + ["A3", "B3", "C3", "D3", "E3", "F3", "G3", "H3"], + ["A4", "B4", "C4", "D4", "E4", "F4", "G4", "H4"], + ["A5", "B5", "C5", "D5", "E5", "F5", "G5", "H5"], + ["A6", "B6", "C6", "D6", "E6", "F6", "G6", "H6"], + ["A7", "B7", "C7", "D7", "E7", "F7", "G7", "H7"], + ["A8", "B8", "C8", "D8", "E8", "F8", "G8", "H8"], + ["A9", "B9", "C9", "D9", "E9", "F9", "G9", "H9"], + ["A10", "B10", "C10", "D10", "E10", "F10", "G10", "H10"], + ["A11", "B11", "C11", "D11", "E11", "F11", "G11", "H11"], + ["A12", "B12", "C12", "D12", "E12", "F12", "G12", "H12"] + ], + "brand": { + "brand": "Hellma", + "brandId": ["666-R013 Reference Plate"] + }, + "metadata": { + "displayName": "Hellma Reference Plate", + "displayCategory": "wellPlate", + "displayVolumeUnits": "µL", + "tags": [] + }, + "dimensions": { + "xDimension": 127, + "yDimension": 85.5, + "zDimension": 13 + }, + "wells": { + "A1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 74.26, + "z": 12 + }, + "B1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 65.26, + "z": 12 + }, + "C1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 56.26, + "z": 12 + }, + "D1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 47.26, + "z": 12 + }, + "E1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 38.26, + "z": 12 + }, + "F1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 29.26, + "z": 12 + }, + "G1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 20.26, + "z": 12 + }, + "H1": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 14.38, + "y": 11.26, + "z": 12 + }, + "A2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 74.26, + "z": 12 + }, + "B2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 65.26, + "z": 12 + }, + "C2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 56.26, + "z": 12 + }, + "D2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 47.26, + "z": 12 + }, + "E2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 38.26, + "z": 12 + }, + "F2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 29.26, + "z": 12 + }, + "G2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 20.26, + "z": 12 + }, + "H2": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 23.38, + "y": 11.26, + "z": 12 + }, + "A3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 74.26, + "z": 12 + }, + "B3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 65.26, + "z": 12 + }, + "C3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 56.26, + "z": 12 + }, + "D3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 47.26, + "z": 12 + }, + "E3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 38.26, + "z": 12 + }, + "F3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 29.26, + "z": 12 + }, + "G3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 20.26, + "z": 12 + }, + "H3": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 32.38, + "y": 11.26, + "z": 12 + }, + "A4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 74.26, + "z": 12 + }, + "B4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 65.26, + "z": 12 + }, + "C4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 56.26, + "z": 12 + }, + "D4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 47.26, + "z": 12 + }, + "E4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 38.26, + "z": 12 + }, + "F4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 29.26, + "z": 12 + }, + "G4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 20.26, + "z": 12 + }, + "H4": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 41.38, + "y": 11.26, + "z": 12 + }, + "A5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 74.26, + "z": 12 + }, + "B5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 65.26, + "z": 12 + }, + "C5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 56.26, + "z": 12 + }, + "D5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 47.26, + "z": 12 + }, + "E5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 38.26, + "z": 12 + }, + "F5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 29.26, + "z": 12 + }, + "G5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 20.26, + "z": 12 + }, + "H5": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 50.38, + "y": 11.26, + "z": 12 + }, + "A6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 74.26, + "z": 12 + }, + "B6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 65.26, + "z": 12 + }, + "C6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 56.26, + "z": 12 + }, + "D6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 47.26, + "z": 12 + }, + "E6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 38.26, + "z": 12 + }, + "F6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 29.26, + "z": 12 + }, + "G6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 20.26, + "z": 12 + }, + "H6": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 59.38, + "y": 11.26, + "z": 12 + }, + "A7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 74.26, + "z": 12 + }, + "B7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 65.26, + "z": 12 + }, + "C7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 56.26, + "z": 12 + }, + "D7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 47.26, + "z": 12 + }, + "E7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 38.26, + "z": 12 + }, + "F7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 29.26, + "z": 12 + }, + "G7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 20.26, + "z": 12 + }, + "H7": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 68.38, + "y": 11.26, + "z": 12 + }, + "A8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 74.26, + "z": 12 + }, + "B8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 65.26, + "z": 12 + }, + "C8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 56.26, + "z": 12 + }, + "D8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 47.26, + "z": 12 + }, + "E8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 38.26, + "z": 12 + }, + "F8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 29.26, + "z": 12 + }, + "G8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 20.26, + "z": 12 + }, + "H8": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 77.38, + "y": 11.26, + "z": 12 + }, + "A9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 74.26, + "z": 12 + }, + "B9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 65.26, + "z": 12 + }, + "C9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 56.26, + "z": 12 + }, + "D9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 47.26, + "z": 12 + }, + "E9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 38.26, + "z": 12 + }, + "F9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 29.26, + "z": 12 + }, + "G9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 20.26, + "z": 12 + }, + "H9": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 86.38, + "y": 11.26, + "z": 12 + }, + "A10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 74.26, + "z": 12 + }, + "B10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 65.26, + "z": 12 + }, + "C10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 56.26, + "z": 12 + }, + "D10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 47.26, + "z": 12 + }, + "E10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 38.26, + "z": 12 + }, + "F10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 29.26, + "z": 12 + }, + "G10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 20.26, + "z": 12 + }, + "H10": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 95.38, + "y": 11.26, + "z": 12 + }, + "A11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 74.26, + "z": 12 + }, + "B11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 65.26, + "z": 12 + }, + "C11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 56.26, + "z": 12 + }, + "D11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 47.26, + "z": 12 + }, + "E11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 38.26, + "z": 12 + }, + "F11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 29.26, + "z": 12 + }, + "G11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 20.26, + "z": 12 + }, + "H11": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 104.38, + "y": 11.26, + "z": 12 + }, + "A12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 74.26, + "z": 12 + }, + "B12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 65.26, + "z": 12 + }, + "C12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 56.26, + "z": 12 + }, + "D12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 47.26, + "z": 12 + }, + "E12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 38.26, + "z": 12 + }, + "F12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 29.26, + "z": 12 + }, + "G12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 20.26, + "z": 12 + }, + "H12": { + "depth": 1, + "totalLiquidVolume": 1, + "shape": "circular", + "diameter": 6.6, + "x": 113.38, + "y": 11.26, + "z": 12 + } + }, + "groups": [ + { + "metadata": { + "wellBottomShape": "flat" + }, + "wells": [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1", + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2", + "A3", + "B3", + "C3", + "D3", + "E3", + "F3", + "G3", + "H3", + "A4", + "B4", + "C4", + "D4", + "E4", + "F4", + "G4", + "H4", + "A5", + "B5", + "C5", + "D5", + "E5", + "F5", + "G5", + "H5", + "A6", + "B6", + "C6", + "D6", + "E6", + "F6", + "G6", + "H6", + "A7", + "B7", + "C7", + "D7", + "E7", + "F7", + "G7", + "H7", + "A8", + "B8", + "C8", + "D8", + "E8", + "F8", + "G8", + "H8", + "A9", + "B9", + "C9", + "D9", + "E9", + "F9", + "G9", + "H9", + "A10", + "B10", + "C10", + "D10", + "E10", + "F10", + "G10", + "H10", + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11", + "A12", + "B12", + "C12", + "D12", + "E12", + "F12", + "G12", + "H12" + ] } + ], + "parameters": { + "format": "irregular", + "quirks": [], + "isTiprack": false, + "isMagneticModuleCompatible": false, + "loadName": "hellma_reference_plate" + }, + "namespace": "custom_beta", + "version": 1, + "schemaVersion": 2, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } } - diff --git a/abr-testing/abr_testing/protocols/helpers.py b/abr-testing/abr_testing/protocols/helpers.py index e63cd0b5ce7..c3b1b7f217d 100644 --- a/abr-testing/abr_testing/protocols/helpers.py +++ b/abr-testing/abr_testing/protocols/helpers.py @@ -371,7 +371,7 @@ def find_liquid_height_of_loaded_liquids( well for items in liquid_vols_and_wells.values() for entry in items - if isinstance(entry["well"], (Well, list)) and entry["volume"] != 0 + if isinstance(entry["well"], (Well, list)) and entry["volume"] != 0.0 # Ensure "well" is Well or list of Well for well in ( entry["well"] if isinstance(entry["well"], list) else [entry["well"]] diff --git a/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py b/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py index b32abb1f81d..c6ded28719d 100644 --- a/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py +++ b/abr-testing/abr_testing/protocols/liquid_setups/9_Thermo MagMax RNA Extraction Liquid Setup.py @@ -38,7 +38,7 @@ def run(protocol: protocol_api.ProtocolContext) -> None: well1 = 8120 / 8 well2 = 6400 / 8 well3_7 = 8550 / 8 - sample_vol = 60 + sample_vol = 100 # Reservoir p1000.transfer( @@ -97,12 +97,12 @@ def run(protocol: protocol_api.ProtocolContext) -> None: volume=[sample_vol, sample_vol, sample_vol, sample_vol, sample_vol, sample_vol], source=source_reservoir["A1"].bottom(z=0.2), dest=[ - sample_plate["A7"].top(), - sample_plate["A8"].top(), - sample_plate["A9"].top(), - sample_plate["A10"].top(), - sample_plate["A11"].top(), - sample_plate["A12"].top(), + sample_plate["A1"].top(), + sample_plate["A2"].top(), + sample_plate["A3"].top(), + sample_plate["A4"].top(), + sample_plate["A5"].top(), + sample_plate["A6"].top(), ], blow_out=True, blowout_location="source well", From 5d848677a27f873fe390ca15bf831536c0767396 Mon Sep 17 00:00:00 2001 From: rclarke0 Date: Fri, 8 Nov 2024 10:28:23 -0500 Subject: [PATCH 12/13] format fixes --- .../active_protocols/12_KAPA HyperPlus Library Prep.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py b/abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py index 03fd2d9769c..1629b6c6626 100644 --- a/abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py +++ b/abr-testing/abr_testing/protocols/active_protocols/12_KAPA HyperPlus Library Prep.py @@ -156,7 +156,6 @@ def run(ctx: ProtocolContext) -> None: trash = ctx.load_waste_chute() unused_lids: List[Labware] = [] - used_lids:List[Labware] = [] # Load TC Lids if disposable_lid: unused_lids = helpers.load_disposable_lids(ctx, 5, ["C3"]) @@ -655,7 +654,7 @@ def run_amplification_profile( return unused_lids, used_lids def mix_beads( - pip: InstrumentContext, res: Well, vol: int, reps: int, col: int + pip: InstrumentContext, res: Well, vol: float, reps: int, col: int ) -> None: """Mix beads function.""" # Multiplier tells From 13a309f998fe28f8665eed27db9e784cb9d41bff Mon Sep 17 00:00:00 2001 From: Seth Foster Date: Fri, 8 Nov 2024 10:29:14 -0500 Subject: [PATCH 13/13] fix: also this ignore --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ffdbb8509c0..d3ddd15f359 100755 --- a/Makefile +++ b/Makefile @@ -228,7 +228,7 @@ lint-js-prettier: .PHONY: lint-json lint-json: - yarn eslint --max-warnings 0 --ext .json . + yarn eslint --ignore-pattern "abr-testing/protocols/" --max-warnings 0 --ext .json . .PHONY: lint-css lint-css: