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