From 9c303441f08f9807e8d4fa3e0039fc832b962c26 Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Thu, 9 Nov 2023 17:07:39 -0500 Subject: [PATCH 1/2] fix parsing logic for media volumes --- protoBuilds/0909e6/media_transfer.ot2.apiv2.py.json | 2 +- protocols/0909e6/media_transfer.ot2.apiv2.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/protoBuilds/0909e6/media_transfer.ot2.apiv2.py.json b/protoBuilds/0909e6/media_transfer.ot2.apiv2.py.json index 1710ea15c..df864143c 100644 --- a/protoBuilds/0909e6/media_transfer.ot2.apiv2.py.json +++ b/protoBuilds/0909e6/media_transfer.ot2.apiv2.py.json @@ -1,5 +1,5 @@ { - "content": "import math\nfrom opentrons.protocol_api.labware import Well\nfrom opentrons.protocols.api_support.types import APIVersion\nfrom opentrons.types import Point\n\nmetadata = {\n 'protocolName': 'DOE',\n 'author': 'Nick self.min_height:\n self.height = self.height - dh\n else:\n self.height = self.min_height\n if self.current_volume - vol > 0:\n self.current_volume = self.current_volume - vol\n else:\n self.current_volume = 0\n return self.well.bottom(self.height)\n\n def height_inc(self, vol):\n dh = (vol/(math.pi*(self.radius**2)))*self.comp_coeff\n if self.height + dh < self.depth:\n self.height = self.height + dh\n else:\n self.height = self.depth\n self.current_volume += vol\n return self.well.bottom(self.height + 20)\n\n # labware\n tuberack50 = ctx.load_labware('opentrons_6_tuberack_falcon_50ml_conical',\n '1', 'media tuberack')\n tuberacks15 = [\n ctx.load_labware(\n 'opentrons_15_tuberack_falcon_15ml_conical', slot,\n f'factors {tube_set}')\n for i, (slot, tube_set) in enumerate(\n zip(['4', '7'], ['1-15', '16-30']))]\n tuberacks2 = [\n ctx.load_labware(\n 'opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap', slot,\n f'factors {tube_set}')\n for i, (slot, tube_set) in enumerate(\n zip(['5', '8'], ['31-54', '55-78']))]\n plate = ctx.load_labware('usascientific_96_wellplate_2.4ml_deep', '2')\n tiprack_small = [ctx.load_labware(tiprack_small_type, '3')]\n tiprack1000 = [\n ctx.load_labware('opentrons_96_filtertiprack_1000ul', slot)\n for slot in ['6']]\n\n # pipettes\n pip_small = ctx.load_instrument(type_pipette_small, 'left',\n tip_racks=tiprack_small)\n p1000 = ctx.load_instrument('p1000_single_gen2', 'right',\n tip_racks=tiprack1000)\n\n # reagents\n vol_media_list = [float(val) for val in vol_media_tubes.split(',')]\n media_rows_ordered = [tube for row in tuberack50.rows() for tube in row]\n media = [\n WellH(well, current_volume=vol, height=well.depth*(vol/50000)*0.9)\n for well, vol in zip(\n media_rows_ordered[:len(vol_media_list)],\n [vol_media_tube*1000 for vol_media_tube in vol_media_list])]\n\n # parse data\n factor_data = [\n [float(val) for val in line.split(',')[1:] if val.strip()]\n for line in csv_factors.splitlines()[3:]\n ]\n\n all_factor_tubes = [\n well for rack_set in [tuberacks15, tuberacks2]\n for rack in rack_set\n for well in rack.wells()]\n\n factor_indices = [\n int(cell.strip().split(' ')[-1]) - 1\n for cell in csv_factors.splitlines()[0].split(',')[1:]\n if cell.strip()]\n factor_tubes = [\n all_factor_tubes[ind] for ind in factor_indices]\n factor_viscosities = [\n bool(visc) for visc in csv_factors.splitlines()[1].split(',')[1:]\n if visc.strip()]\n factor_volumes_ul = [\n float(cell)*1000 for cell in csv_factors.splitlines()[2].split(',')[1:]\n if cell.strip()]\n # ref_vol = tuberacks15[0].wells()[0].max_volume / 1000 # 2ml or 15ml\n # ref_height = tuberacks15[0].wells()[0].depth\n factor_heights = [\n # ensure tip is submerged\n round(factor_vol/(factor_tube.max_volume)*factor_tube.depth*0.9,\n 1)\n for factor_tube, factor_vol in zip(factor_tubes, factor_volumes_ul)]\n factors = [\n WellH(well, current_volume=vol, height=height)\n for well, vol, height in zip(\n factor_tubes, factor_volumes_ul, factor_heights)]\n\n def slow_withdraw(well, pip=p1000, delay_s=2.0):\n ctx.max_speeds['A'] = 25\n ctx.max_speeds['Z'] = 25\n if delay_s > 0:\n ctx.delay(seconds=delay_s)\n pip.move_to(well.top())\n del ctx.max_speeds['A']\n del ctx.max_speeds['Z']\n\n def split_media_vol(vol):\n num_transfers = math.ceil(vol/(1000-vol_pre_airgap_1000))\n vol_per_transfer = round(vol/num_transfers, 1)\n return [vol_per_transfer]*num_transfers\n\n # iterate\n iterator_media = iter(media)\n current_media = next(iterator_media)\n\n def check_media(vol):\n nonlocal current_media\n if current_media.current_volume - vol < current_media.min_vol:\n current_media = next(iterator_media)\n\n def custom_distribute(info, pip):\n pip_volume = pip.tip_racks[0].wells()[0].max_volume\n vol_pre_airgap = vol_pre_airgap_small if pip == \\\n pip_small else vol_pre_airgap_1000\n max_vol = pip_volume\n sets = []\n running = []\n current_vol = 0\n for d in info:\n well = [key for key in d.keys()][0]\n vol = [val for val in d.values()][0]\n if vol > 0:\n if current_vol + vol + vol_pre_airgap > max_vol:\n sets.append(running)\n running = []\n current_vol = 0\n running.append({well: vol})\n current_vol += vol + vol_pre_airgap\n sets.append(running)\n return sets\n\n # transfer media\n p1000.pick_up_tip()\n wells_ordered = [well for row in plate.rows() for well in row]\n vols_media = [\n float(line.split(',')[0]) for line in csv_factors.splitlines()[2:]]\n media_info = []\n for well, vol_media in zip(wells_ordered, vols_media):\n vols_split = split_media_vol(vol_media)\n for vol in vols_split:\n media_info.append({well: vol})\n\n wells_h = [\n WellH(well, height=0) for well in wells_ordered]\n\n for d in media_info:\n well = list(d.keys())[0]\n asp_vol = list(d.values())[0]\n if p1000.current_volume:\n p1000.dispense(p1000.current_volume, current_media.well.top())\n check_media(asp_vol)\n p1000.aspirate(vol_pre_airgap_1000, current_media.well.top())\n p1000.aspirate(asp_vol, current_media.height_dec(asp_vol))\n slow_withdraw(current_media.well, p1000)\n p1000.dispense(p1000.current_volume, well.bottom(well.depth/2))\n p1000.blow_out(well.bottom(well.depth/2))\n slow_withdraw(well, p1000)\n\n # media_sets = custom_distribute(media_info, pip=p1000)\n # for media_set in media_sets:\n # if p1000.current_volume:\n # p1000.dispense(p1000.current_volume, current_media.well.top())\n # # pre-air_gap to fully void tip on blow_out\n # for d in media_set:\n # asp_vol = sum(d.values())\n # check_media(asp_vol)\n # p1000.aspirate(vol_pre_airgap_1000, current_media.well.top())\n # p1000.aspirate(asp_vol, current_media.height_dec(asp_vol))\n # slow_withdraw(current_media.well, p1000)\n # for i, d in enumerate(media_set):\n # well = [key for key in d.keys()][0]\n # vol = [val for val in d.values()][0]\n # p1000.dispense(vol+vol_pre_airgap_1000,\n # well.bottom(well.depth/2))\n # if i == len(media_set) - 1:\n # p1000.blow_out(well.bottom(well.depth/2))\n # slow_withdraw(well, p1000)\n p1000.return_tip()\n p1000.reset_tipracks()\n\n viscosity_map = {\n 20: {\n 'aspirate': 6.5,\n 'delay_aspiration': 2.0,\n 'dispense': 6.5,\n 'delay_dispense': 2.0,\n 'default': 7.56\n },\n 300: {\n 'aspirate': 80,\n 'delay_aspiration': 2.0,\n 'dispense': 80,\n 'delay_dispense': 2.0,\n 'default': 92.86\n },\n 1000: {\n 'aspirate': 247,\n 'delay_aspiration': 2.0,\n 'dispense': 247,\n 'delay_dispense': 2.0,\n 'default': 247\n }\n }\n\n # transfer factors\n for i, (visc, factor) in enumerate(zip(factor_viscosities, factors)):\n factor_vols = [line[i] for line in factor_data]\n factor_info = [\n {well: vol}\n for well, vol in zip(wells_h, factor_vols)]\n factor_sets = custom_distribute(factor_info, pip=pip_small)\n if visc:\n asp_rate_relative = viscosity_map[\n int(pip_small.max_volume)]['aspirate'] / (\n viscosity_map[int(pip_small.max_volume)]['default'])\n asp_delay = viscosity_map[\n int(pip_small.max_volume)]['delay_aspiration']\n disp_rate_relative = viscosity_map[\n int(pip_small.max_volume)]['dispense'] / (\n viscosity_map[int(pip_small.max_volume)]['default'])\n disp_delay = viscosity_map[\n int(pip_small.max_volume)]['delay_dispense']\n else:\n asp_rate_relative = 1\n asp_delay = 2.0\n disp_rate_relative = 1\n disp_delay = 2.0\n for factor_set in factor_sets:\n # aspirate total vol needed\n if not pip_small.has_tip:\n pip_small.pick_up_tip()\n # pre-air_gap to fully void tip on blow_out\n for d in factor_set:\n well = [k for k in d.keys()][0]\n asp_vol = [k for k in d.values()][0]\n if asp_vol + vol_pre_airgap_small <= pip_small.max_volume:\n ag_vol = vol_pre_airgap_small\n else:\n ag_vol = pip_small.max_volume - asp_vol\n pip_small.aspirate(ag_vol, factor.well.top())\n pip_small.aspirate(\n asp_vol, factor.height_dec(asp_vol),\n rate=asp_rate_relative)\n slow_withdraw(factor.well, pip_small, delay_s=asp_delay)\n pip_small.dispense(\n pip_small.current_volume,\n well.height_inc(asp_vol).move(Point(z=3)),\n rate=disp_rate_relative)\n ctx.delay(seconds=disp_delay)\n pip_small.blow_out(well.top(-2))\n\n # total_factor_vol = sum([sum(dict.values()) for dict in\n # factor_set])\n # p300.aspirate(total_factor_vol,\n # factor.height_dec(total_factor_vol))\n # for i, dict in enumerate(factor_set):\n # for well, vol in dict.items():\n # pip_small.dispense(\n # vol+vol_pre_airgap_small, well.bottom(well.depth/2))\n # if i == len(factor_set) - 1:\n # pip_small.blow_out(well.top(-2))\n\n # for d in factor_set:\n # asp_vol = sum(d.values())\n # if asp_vol + vol_pre_airgap_small <= pip_small.max_volume:\n # ag_vol = vol_pre_airgap_small\n # else:\n # ag_vol = pip_small.max_volume - asp_vol\n # pip_small.aspirate(ag_vol, factor.well.top())\n # pip_small.aspirate(asp_vol, factor.height_dec(asp_vol))\n # # total_factor_vol = sum([sum(dict.values()) for dict in\n # # factor_set])\n # # p300.aspirate(total_factor_vol,\n # # factor.height_dec(total_factor_vol))\n # slow_withdraw(factor.well, pip_small)\n # for i, dict in enumerate(factor_set):\n # for well, vol in dict.items():\n # pip_small.dispense(\n # vol+vol_pre_airgap_small, well.bottom(well.depth/2))\n # if i == len(factor_set) - 1:\n # pip_small.blow_out(well.top(-2))\n if pip_small.has_tip:\n pip_small.drop_tip()\n\n # mix\n for well in plate.wells()[:len(factor_data)]:\n p1000.pick_up_tip()\n p1000.mix(reps_mix, vol_mix, well.bottom(2))\n slow_withdraw(well, p1000)\n p1000.drop_tip()\n", + "content": "import math\nfrom opentrons.protocol_api.labware import Well\nfrom opentrons.protocols.api_support.types import APIVersion\nfrom opentrons.types import Point\n\nmetadata = {\n 'protocolName': 'DOE',\n 'author': 'Nick self.min_height:\n self.height = self.height - dh\n else:\n self.height = self.min_height\n if self.current_volume - vol > 0:\n self.current_volume = self.current_volume - vol\n else:\n self.current_volume = 0\n return self.well.bottom(self.height)\n\n def height_inc(self, vol):\n dh = (vol/(math.pi*(self.radius**2)))*self.comp_coeff\n if self.height + dh < self.depth:\n self.height = self.height + dh\n else:\n self.height = self.depth\n self.current_volume += vol\n return self.well.bottom(self.height + 20)\n\n # labware\n tuberack50 = ctx.load_labware('opentrons_6_tuberack_falcon_50ml_conical',\n '1', 'media tuberack')\n tuberacks15 = [\n ctx.load_labware(\n 'opentrons_15_tuberack_falcon_15ml_conical', slot,\n f'factors {tube_set}')\n for i, (slot, tube_set) in enumerate(\n zip(['4', '7'], ['1-15', '16-30']))]\n tuberacks2 = [\n ctx.load_labware(\n 'opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap', slot,\n f'factors {tube_set}')\n for i, (slot, tube_set) in enumerate(\n zip(['5', '8'], ['31-54', '55-78']))]\n plate = ctx.load_labware('usascientific_96_wellplate_2.4ml_deep', '2')\n tiprack_small = [ctx.load_labware(tiprack_small_type, '3')]\n tiprack1000 = [\n ctx.load_labware('opentrons_96_filtertiprack_1000ul', slot)\n for slot in ['6']]\n\n # pipettes\n pip_small = ctx.load_instrument(type_pipette_small, 'left',\n tip_racks=tiprack_small)\n p1000 = ctx.load_instrument('p1000_single_gen2', 'right',\n tip_racks=tiprack1000)\n\n # reagents\n vol_media_list = [float(val) for val in vol_media_tubes.split(',')]\n media_rows_ordered = [tube for row in tuberack50.rows() for tube in row]\n media = [\n WellH(well, current_volume=vol, height=well.depth*(vol/50000)*0.9)\n for well, vol in zip(\n media_rows_ordered[:len(vol_media_list)],\n [vol_media_tube*1000 for vol_media_tube in vol_media_list])]\n\n # parse data\n factor_data = [\n [float(val) for val in line.split(',')[1:] if val.strip()]\n for line in csv_factors.splitlines()[3:]\n ]\n\n all_factor_tubes = [\n well for rack_set in [tuberacks15, tuberacks2]\n for rack in rack_set\n for well in rack.wells()]\n\n factor_indices = [\n int(cell.strip().split(' ')[-1]) - 1\n for cell in csv_factors.splitlines()[0].split(',')[1:]\n if cell.strip()]\n factor_tubes = [\n all_factor_tubes[ind] for ind in factor_indices]\n factor_viscosities = [\n bool(visc) for visc in csv_factors.splitlines()[1].split(',')[1:]\n if visc.strip()]\n factor_volumes_ul = [\n float(cell)*1000 for cell in csv_factors.splitlines()[2].split(',')[1:]\n if cell.strip()]\n # ref_vol = tuberacks15[0].wells()[0].max_volume / 1000 # 2ml or 15ml\n # ref_height = tuberacks15[0].wells()[0].depth\n factor_heights = [\n # ensure tip is submerged\n round(factor_vol/(factor_tube.max_volume)*factor_tube.depth*0.9,\n 1)\n for factor_tube, factor_vol in zip(factor_tubes, factor_volumes_ul)]\n factors = [\n WellH(well, current_volume=vol, height=height)\n for well, vol, height in zip(\n factor_tubes, factor_volumes_ul, factor_heights)]\n\n def slow_withdraw(well, pip=p1000, delay_s=2.0):\n ctx.max_speeds['A'] = 25\n ctx.max_speeds['Z'] = 25\n if delay_s > 0:\n ctx.delay(seconds=delay_s)\n pip.move_to(well.top())\n del ctx.max_speeds['A']\n del ctx.max_speeds['Z']\n\n def split_media_vol(vol):\n num_transfers = math.ceil(vol/(1000-vol_pre_airgap_1000))\n vol_per_transfer = round(vol/num_transfers, 1)\n return [vol_per_transfer]*num_transfers\n\n # iterate\n iterator_media = iter(media)\n current_media = next(iterator_media)\n\n def check_media(vol):\n nonlocal current_media\n if current_media.current_volume - vol < current_media.min_vol:\n current_media = next(iterator_media)\n\n def custom_distribute(info, pip):\n pip_volume = pip.tip_racks[0].wells()[0].max_volume\n vol_pre_airgap = vol_pre_airgap_small if pip == \\\n pip_small else vol_pre_airgap_1000\n max_vol = pip_volume\n sets = []\n running = []\n current_vol = 0\n for d in info:\n well = [key for key in d.keys()][0]\n vol = [val for val in d.values()][0]\n if vol > 0:\n if current_vol + vol + vol_pre_airgap > max_vol:\n sets.append(running)\n running = []\n current_vol = 0\n running.append({well: vol})\n current_vol += vol + vol_pre_airgap\n sets.append(running)\n return sets\n\n # transfer media\n p1000.pick_up_tip()\n wells_ordered = [well for row in plate.rows() for well in row]\n vols_media = [\n float(line.split(',')[0]) for line in csv_factors.splitlines()[3:]]\n media_info = []\n for well, vol_media in zip(wells_ordered, vols_media):\n vols_split = split_media_vol(vol_media)\n for vol in vols_split:\n media_info.append({well: vol})\n\n wells_h = [\n WellH(well, height=0) for well in wells_ordered]\n\n for d in media_info:\n well = list(d.keys())[0]\n asp_vol = list(d.values())[0]\n if p1000.current_volume:\n p1000.dispense(p1000.current_volume, current_media.well.top())\n check_media(asp_vol)\n p1000.aspirate(vol_pre_airgap_1000, current_media.well.top())\n p1000.aspirate(asp_vol, current_media.height_dec(asp_vol))\n slow_withdraw(current_media.well, p1000)\n p1000.dispense(p1000.current_volume, well.bottom(well.depth/2))\n p1000.blow_out(well.bottom(well.depth/2))\n slow_withdraw(well, p1000)\n\n # media_sets = custom_distribute(media_info, pip=p1000)\n # for media_set in media_sets:\n # if p1000.current_volume:\n # p1000.dispense(p1000.current_volume, current_media.well.top())\n # # pre-air_gap to fully void tip on blow_out\n # for d in media_set:\n # asp_vol = sum(d.values())\n # check_media(asp_vol)\n # p1000.aspirate(vol_pre_airgap_1000, current_media.well.top())\n # p1000.aspirate(asp_vol, current_media.height_dec(asp_vol))\n # slow_withdraw(current_media.well, p1000)\n # for i, d in enumerate(media_set):\n # well = [key for key in d.keys()][0]\n # vol = [val for val in d.values()][0]\n # p1000.dispense(vol+vol_pre_airgap_1000,\n # well.bottom(well.depth/2))\n # if i == len(media_set) - 1:\n # p1000.blow_out(well.bottom(well.depth/2))\n # slow_withdraw(well, p1000)\n p1000.return_tip()\n p1000.reset_tipracks()\n\n viscosity_map = {\n 20: {\n 'aspirate': 6.5,\n 'delay_aspiration': 2.0,\n 'dispense': 6.5,\n 'delay_dispense': 2.0,\n 'default': 7.56\n },\n 300: {\n 'aspirate': 80,\n 'delay_aspiration': 2.0,\n 'dispense': 80,\n 'delay_dispense': 2.0,\n 'default': 92.86\n },\n 1000: {\n 'aspirate': 247,\n 'delay_aspiration': 2.0,\n 'dispense': 247,\n 'delay_dispense': 2.0,\n 'default': 247\n }\n }\n\n # transfer factors\n for i, (visc, factor) in enumerate(zip(factor_viscosities, factors)):\n factor_vols = [line[i] for line in factor_data]\n factor_info = [\n {well: vol}\n for well, vol in zip(wells_h, factor_vols)]\n factor_sets = custom_distribute(factor_info, pip=pip_small)\n if visc:\n asp_rate_relative = viscosity_map[\n int(pip_small.max_volume)]['aspirate'] / (\n viscosity_map[int(pip_small.max_volume)]['default'])\n asp_delay = viscosity_map[\n int(pip_small.max_volume)]['delay_aspiration']\n disp_rate_relative = viscosity_map[\n int(pip_small.max_volume)]['dispense'] / (\n viscosity_map[int(pip_small.max_volume)]['default'])\n disp_delay = viscosity_map[\n int(pip_small.max_volume)]['delay_dispense']\n else:\n asp_rate_relative = 1\n asp_delay = 2.0\n disp_rate_relative = 1\n disp_delay = 2.0\n for factor_set in factor_sets:\n # aspirate total vol needed\n if not pip_small.has_tip:\n pip_small.pick_up_tip()\n # pre-air_gap to fully void tip on blow_out\n for d in factor_set:\n well = [k for k in d.keys()][0]\n asp_vol = [k for k in d.values()][0]\n if asp_vol + vol_pre_airgap_small <= pip_small.max_volume:\n ag_vol = vol_pre_airgap_small\n else:\n ag_vol = pip_small.max_volume - asp_vol\n pip_small.aspirate(ag_vol, factor.well.top())\n pip_small.aspirate(\n asp_vol, factor.height_dec(asp_vol),\n rate=asp_rate_relative)\n slow_withdraw(factor.well, pip_small, delay_s=asp_delay)\n pip_small.dispense(\n pip_small.current_volume,\n well.height_inc(asp_vol).move(Point(z=3)),\n rate=disp_rate_relative)\n ctx.delay(seconds=disp_delay)\n pip_small.blow_out(well.top(-2))\n\n # total_factor_vol = sum([sum(dict.values()) for dict in\n # factor_set])\n # p300.aspirate(total_factor_vol,\n # factor.height_dec(total_factor_vol))\n # for i, dict in enumerate(factor_set):\n # for well, vol in dict.items():\n # pip_small.dispense(\n # vol+vol_pre_airgap_small, well.bottom(well.depth/2))\n # if i == len(factor_set) - 1:\n # pip_small.blow_out(well.top(-2))\n\n # for d in factor_set:\n # asp_vol = sum(d.values())\n # if asp_vol + vol_pre_airgap_small <= pip_small.max_volume:\n # ag_vol = vol_pre_airgap_small\n # else:\n # ag_vol = pip_small.max_volume - asp_vol\n # pip_small.aspirate(ag_vol, factor.well.top())\n # pip_small.aspirate(asp_vol, factor.height_dec(asp_vol))\n # # total_factor_vol = sum([sum(dict.values()) for dict in\n # # factor_set])\n # # p300.aspirate(total_factor_vol,\n # # factor.height_dec(total_factor_vol))\n # slow_withdraw(factor.well, pip_small)\n # for i, dict in enumerate(factor_set):\n # for well, vol in dict.items():\n # pip_small.dispense(\n # vol+vol_pre_airgap_small, well.bottom(well.depth/2))\n # if i == len(factor_set) - 1:\n # pip_small.blow_out(well.top(-2))\n if pip_small.has_tip:\n pip_small.drop_tip()\n\n # mix\n for well in plate.wells()[:len(factor_data)]:\n p1000.pick_up_tip()\n p1000.mix(reps_mix, vol_mix, well.bottom(2))\n slow_withdraw(well, p1000)\n p1000.drop_tip()\n", "custom_labware_defs": [], "fields": [ { diff --git a/protocols/0909e6/media_transfer.ot2.apiv2.py b/protocols/0909e6/media_transfer.ot2.apiv2.py index b67c22805..c1bf70129 100644 --- a/protocols/0909e6/media_transfer.ot2.apiv2.py +++ b/protocols/0909e6/media_transfer.ot2.apiv2.py @@ -181,7 +181,7 @@ def custom_distribute(info, pip): p1000.pick_up_tip() wells_ordered = [well for row in plate.rows() for well in row] vols_media = [ - float(line.split(',')[0]) for line in csv_factors.splitlines()[2:]] + float(line.split(',')[0]) for line in csv_factors.splitlines()[3:]] media_info = [] for well, vol_media in zip(wells_ordered, vols_media): vols_split = split_media_vol(vol_media) From 82a3e0950eb6e3c5fb05f9eb99e210f7aa385101 Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Thu, 9 Nov 2023 17:07:50 -0500 Subject: [PATCH 2/2] fix parsing logic for media volumes --- .../0909e6/media_transfer.ot2.apiv2.py.json | 224 +++++++++--------- 1 file changed, 112 insertions(+), 112 deletions(-) diff --git a/protoBuilds/0909e6/media_transfer.ot2.apiv2.py.json b/protoBuilds/0909e6/media_transfer.ot2.apiv2.py.json index df864143c..ed791824e 100644 --- a/protoBuilds/0909e6/media_transfer.ot2.apiv2.py.json +++ b/protoBuilds/0909e6/media_transfer.ot2.apiv2.py.json @@ -1,118 +1,118 @@ { - "content": "import math\nfrom opentrons.protocol_api.labware import Well\nfrom opentrons.protocols.api_support.types import APIVersion\nfrom opentrons.types import Point\n\nmetadata = {\n 'protocolName': 'DOE',\n 'author': 'Nick self.min_height:\n self.height = self.height - dh\n else:\n self.height = self.min_height\n if self.current_volume - vol > 0:\n self.current_volume = self.current_volume - vol\n else:\n self.current_volume = 0\n return self.well.bottom(self.height)\n\n def height_inc(self, vol):\n dh = (vol/(math.pi*(self.radius**2)))*self.comp_coeff\n if self.height + dh < self.depth:\n self.height = self.height + dh\n else:\n self.height = self.depth\n self.current_volume += vol\n return self.well.bottom(self.height + 20)\n\n # labware\n tuberack50 = ctx.load_labware('opentrons_6_tuberack_falcon_50ml_conical',\n '1', 'media tuberack')\n tuberacks15 = [\n ctx.load_labware(\n 'opentrons_15_tuberack_falcon_15ml_conical', slot,\n f'factors {tube_set}')\n for i, (slot, tube_set) in enumerate(\n zip(['4', '7'], ['1-15', '16-30']))]\n tuberacks2 = [\n ctx.load_labware(\n 'opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap', slot,\n f'factors {tube_set}')\n for i, (slot, tube_set) in enumerate(\n zip(['5', '8'], ['31-54', '55-78']))]\n plate = ctx.load_labware('usascientific_96_wellplate_2.4ml_deep', '2')\n tiprack_small = [ctx.load_labware(tiprack_small_type, '3')]\n tiprack1000 = [\n ctx.load_labware('opentrons_96_filtertiprack_1000ul', slot)\n for slot in ['6']]\n\n # pipettes\n pip_small = ctx.load_instrument(type_pipette_small, 'left',\n tip_racks=tiprack_small)\n p1000 = ctx.load_instrument('p1000_single_gen2', 'right',\n tip_racks=tiprack1000)\n\n # reagents\n vol_media_list = [float(val) for val in vol_media_tubes.split(',')]\n media_rows_ordered = [tube for row in tuberack50.rows() for tube in row]\n media = [\n WellH(well, current_volume=vol, height=well.depth*(vol/50000)*0.9)\n for well, vol in zip(\n media_rows_ordered[:len(vol_media_list)],\n [vol_media_tube*1000 for vol_media_tube in vol_media_list])]\n\n # parse data\n factor_data = [\n [float(val) for val in line.split(',')[1:] if val.strip()]\n for line in csv_factors.splitlines()[3:]\n ]\n\n all_factor_tubes = [\n well for rack_set in [tuberacks15, tuberacks2]\n for rack in rack_set\n for well in rack.wells()]\n\n factor_indices = [\n int(cell.strip().split(' ')[-1]) - 1\n for cell in csv_factors.splitlines()[0].split(',')[1:]\n if cell.strip()]\n factor_tubes = [\n all_factor_tubes[ind] for ind in factor_indices]\n factor_viscosities = [\n bool(visc) for visc in csv_factors.splitlines()[1].split(',')[1:]\n if visc.strip()]\n factor_volumes_ul = [\n float(cell)*1000 for cell in csv_factors.splitlines()[2].split(',')[1:]\n if cell.strip()]\n # ref_vol = tuberacks15[0].wells()[0].max_volume / 1000 # 2ml or 15ml\n # ref_height = tuberacks15[0].wells()[0].depth\n factor_heights = [\n # ensure tip is submerged\n round(factor_vol/(factor_tube.max_volume)*factor_tube.depth*0.9,\n 1)\n for factor_tube, factor_vol in zip(factor_tubes, factor_volumes_ul)]\n factors = [\n WellH(well, current_volume=vol, height=height)\n for well, vol, height in zip(\n factor_tubes, factor_volumes_ul, factor_heights)]\n\n def slow_withdraw(well, pip=p1000, delay_s=2.0):\n ctx.max_speeds['A'] = 25\n ctx.max_speeds['Z'] = 25\n if delay_s > 0:\n ctx.delay(seconds=delay_s)\n pip.move_to(well.top())\n del ctx.max_speeds['A']\n del ctx.max_speeds['Z']\n\n def split_media_vol(vol):\n num_transfers = math.ceil(vol/(1000-vol_pre_airgap_1000))\n vol_per_transfer = round(vol/num_transfers, 1)\n return [vol_per_transfer]*num_transfers\n\n # iterate\n iterator_media = iter(media)\n current_media = next(iterator_media)\n\n def check_media(vol):\n nonlocal current_media\n if current_media.current_volume - vol < current_media.min_vol:\n current_media = next(iterator_media)\n\n def custom_distribute(info, pip):\n pip_volume = pip.tip_racks[0].wells()[0].max_volume\n vol_pre_airgap = vol_pre_airgap_small if pip == \\\n pip_small else vol_pre_airgap_1000\n max_vol = pip_volume\n sets = []\n running = []\n current_vol = 0\n for d in info:\n well = [key for key in d.keys()][0]\n vol = [val for val in d.values()][0]\n if vol > 0:\n if current_vol + vol + vol_pre_airgap > max_vol:\n sets.append(running)\n running = []\n current_vol = 0\n running.append({well: vol})\n current_vol += vol + vol_pre_airgap\n sets.append(running)\n return sets\n\n # transfer media\n p1000.pick_up_tip()\n wells_ordered = [well for row in plate.rows() for well in row]\n vols_media = [\n float(line.split(',')[0]) for line in csv_factors.splitlines()[3:]]\n media_info = []\n for well, vol_media in zip(wells_ordered, vols_media):\n vols_split = split_media_vol(vol_media)\n for vol in vols_split:\n media_info.append({well: vol})\n\n wells_h = [\n WellH(well, height=0) for well in wells_ordered]\n\n for d in media_info:\n well = list(d.keys())[0]\n asp_vol = list(d.values())[0]\n if p1000.current_volume:\n p1000.dispense(p1000.current_volume, current_media.well.top())\n check_media(asp_vol)\n p1000.aspirate(vol_pre_airgap_1000, current_media.well.top())\n p1000.aspirate(asp_vol, current_media.height_dec(asp_vol))\n slow_withdraw(current_media.well, p1000)\n p1000.dispense(p1000.current_volume, well.bottom(well.depth/2))\n p1000.blow_out(well.bottom(well.depth/2))\n slow_withdraw(well, p1000)\n\n # media_sets = custom_distribute(media_info, pip=p1000)\n # for media_set in media_sets:\n # if p1000.current_volume:\n # p1000.dispense(p1000.current_volume, current_media.well.top())\n # # pre-air_gap to fully void tip on blow_out\n # for d in media_set:\n # asp_vol = sum(d.values())\n # check_media(asp_vol)\n # p1000.aspirate(vol_pre_airgap_1000, current_media.well.top())\n # p1000.aspirate(asp_vol, current_media.height_dec(asp_vol))\n # slow_withdraw(current_media.well, p1000)\n # for i, d in enumerate(media_set):\n # well = [key for key in d.keys()][0]\n # vol = [val for val in d.values()][0]\n # p1000.dispense(vol+vol_pre_airgap_1000,\n # well.bottom(well.depth/2))\n # if i == len(media_set) - 1:\n # p1000.blow_out(well.bottom(well.depth/2))\n # slow_withdraw(well, p1000)\n p1000.return_tip()\n p1000.reset_tipracks()\n\n viscosity_map = {\n 20: {\n 'aspirate': 6.5,\n 'delay_aspiration': 2.0,\n 'dispense': 6.5,\n 'delay_dispense': 2.0,\n 'default': 7.56\n },\n 300: {\n 'aspirate': 80,\n 'delay_aspiration': 2.0,\n 'dispense': 80,\n 'delay_dispense': 2.0,\n 'default': 92.86\n },\n 1000: {\n 'aspirate': 247,\n 'delay_aspiration': 2.0,\n 'dispense': 247,\n 'delay_dispense': 2.0,\n 'default': 247\n }\n }\n\n # transfer factors\n for i, (visc, factor) in enumerate(zip(factor_viscosities, factors)):\n factor_vols = [line[i] for line in factor_data]\n factor_info = [\n {well: vol}\n for well, vol in zip(wells_h, factor_vols)]\n factor_sets = custom_distribute(factor_info, pip=pip_small)\n if visc:\n asp_rate_relative = viscosity_map[\n int(pip_small.max_volume)]['aspirate'] / (\n viscosity_map[int(pip_small.max_volume)]['default'])\n asp_delay = viscosity_map[\n int(pip_small.max_volume)]['delay_aspiration']\n disp_rate_relative = viscosity_map[\n int(pip_small.max_volume)]['dispense'] / (\n viscosity_map[int(pip_small.max_volume)]['default'])\n disp_delay = viscosity_map[\n int(pip_small.max_volume)]['delay_dispense']\n else:\n asp_rate_relative = 1\n asp_delay = 2.0\n disp_rate_relative = 1\n disp_delay = 2.0\n for factor_set in factor_sets:\n # aspirate total vol needed\n if not pip_small.has_tip:\n pip_small.pick_up_tip()\n # pre-air_gap to fully void tip on blow_out\n for d in factor_set:\n well = [k for k in d.keys()][0]\n asp_vol = [k for k in d.values()][0]\n if asp_vol + vol_pre_airgap_small <= pip_small.max_volume:\n ag_vol = vol_pre_airgap_small\n else:\n ag_vol = pip_small.max_volume - asp_vol\n pip_small.aspirate(ag_vol, factor.well.top())\n pip_small.aspirate(\n asp_vol, factor.height_dec(asp_vol),\n rate=asp_rate_relative)\n slow_withdraw(factor.well, pip_small, delay_s=asp_delay)\n pip_small.dispense(\n pip_small.current_volume,\n well.height_inc(asp_vol).move(Point(z=3)),\n rate=disp_rate_relative)\n ctx.delay(seconds=disp_delay)\n pip_small.blow_out(well.top(-2))\n\n # total_factor_vol = sum([sum(dict.values()) for dict in\n # factor_set])\n # p300.aspirate(total_factor_vol,\n # factor.height_dec(total_factor_vol))\n # for i, dict in enumerate(factor_set):\n # for well, vol in dict.items():\n # pip_small.dispense(\n # vol+vol_pre_airgap_small, well.bottom(well.depth/2))\n # if i == len(factor_set) - 1:\n # pip_small.blow_out(well.top(-2))\n\n # for d in factor_set:\n # asp_vol = sum(d.values())\n # if asp_vol + vol_pre_airgap_small <= pip_small.max_volume:\n # ag_vol = vol_pre_airgap_small\n # else:\n # ag_vol = pip_small.max_volume - asp_vol\n # pip_small.aspirate(ag_vol, factor.well.top())\n # pip_small.aspirate(asp_vol, factor.height_dec(asp_vol))\n # # total_factor_vol = sum([sum(dict.values()) for dict in\n # # factor_set])\n # # p300.aspirate(total_factor_vol,\n # # factor.height_dec(total_factor_vol))\n # slow_withdraw(factor.well, pip_small)\n # for i, dict in enumerate(factor_set):\n # for well, vol in dict.items():\n # pip_small.dispense(\n # vol+vol_pre_airgap_small, well.bottom(well.depth/2))\n # if i == len(factor_set) - 1:\n # pip_small.blow_out(well.top(-2))\n if pip_small.has_tip:\n pip_small.drop_tip()\n\n # mix\n for well in plate.wells()[:len(factor_data)]:\n p1000.pick_up_tip()\n p1000.mix(reps_mix, vol_mix, well.bottom(2))\n slow_withdraw(well, p1000)\n p1000.drop_tip()\n", - "custom_labware_defs": [], - "fields": [ - { - "default": "Media Total,Factor 1,Factor 2,Factor 3,Factor 4,Factor 5,Factor 6,Factor 7,Factor 8,Factor 9,Factor 10,Factor 11,Factor 12,\nfactor_volumes (in ml):,5,1.5,7,14,10.1,5,1.5,7,14,10.1,2,2,\n1170,0,0,0,0,0,0,0,0,0,0,65,65,\n1235,0,65,0,0,0,0,0,0,0,0,0,0,\n1040,65,65,0,65,0,0,0,0,0,0,0,65,\n975,0,65,65,65,65,0,0,0,0,0,0,65,\n1053,0,0,65,65,0,52,0,0,0,0,65,0,\n988,0,65,65,0,65,52,0,0,0,0,65,0,\n845,65,65,65,65,0,0,65,0,0,0,65,65,\n910,0,65,0,65,65,0,65,0,0,0,65,65,\n858,65,65,65,0,65,52,65,0,0,0,0,65,\n988,0,0,0,65,65,52,65,0,0,0,0,65,\n1040,0,65,65,0,0,0,0,65,0,0,65,0,\n1105,0,0,0,65,0,0,0,65,0,0,0,65,\n1040,65,0,0,0,65,0,0,65,0,0,0,65,\n923,65,0,65,0,0,52,0,65,0,0,65,65,\n923,0,65,0,65,65,52,0,65,0,0,65,0,\n923,65,0,65,65,65,52,0,65,0,0,0,0,\n975,65,0,0,65,0,0,65,65,0,0,65,0,\n1040,0,0,0,0,65,0,65,65,0,0,65,0,\n910,65,65,65,0,65,0,65,65,0,0,0,0,\n1053,0,0,65,0,0,52,65,65,0,0,0,0,\n858,0,65,65,65,0,52,65,65,0,0,0,65,\n793,65,65,0,0,65,52,65,65,0,0,65,65,\n793,0,0,65,65,65,52,65,65,0,0,65,65,\n975,65,65,65,0,0,0,0,0,65,0,0,65,\n1040,65,0,65,65,0,0,0,0,65,0,0,0,\n910,65,0,0,65,65,0,0,0,65,0,65,65,\n1053,0,65,0,0,0,52,0,0,65,0,0,65,\n728,65,65,65,65,65,52,0,0,65,0,65,65,\n1040,0,0,0,65,0,0,65,0,65,0,0,65,\n910,65,65,0,0,65,0,65,0,65,0,65,0,\n1040,0,0,65,0,65,0,65,0,65,0,0,0,\n858,65,0,65,0,0,52,65,0,65,0,65,65,\n923,65,65,0,65,0,52,65,0,65,0,0,0,\n1105,65,0,0,0,0,0,0,65,65,0,0,0,\n910,65,65,0,65,65,0,0,65,65,0,0,0,\n910,0,0,65,65,65,0,0,65,65,0,65,0,\n923,65,65,0,0,0,52,0,65,65,0,65,0,\n923,0,0,0,0,65,52,0,65,65,0,65,65,\n793,65,65,65,0,65,52,0,65,65,0,0,65,\n910,0,65,65,65,0,0,65,65,65,0,0,0,\n780,0,65,65,0,65,0,65,65,65,0,65,65,\n793,0,65,0,65,0,52,65,65,65,0,65,65,\n793,65,0,65,65,0,52,65,65,65,0,0,65,\n923,0,65,0,0,65,52,65,65,65,0,0,0,\n793,65,0,65,0,65,52,65,65,65,0,65,0,\n1118,0,0,65,0,0,0,0,0,0,52,0,65,\n1118,0,0,0,65,65,0,0,0,0,52,0,0,\n858,65,65,65,65,65,0,0,0,0,52,65,0,\n1001,65,65,65,0,0,52,0,0,0,52,0,0,\n936,0,65,0,65,0,52,0,0,0,52,65,65,\n871,0,0,65,65,65,52,0,0,0,52,65,65,\n988,0,65,65,0,0,0,65,0,0,52,65,0,\n988,65,0,65,65,0,0,65,0,0,52,0,0,\n988,0,65,0,0,65,0,65,0,0,52,0,65,\n858,65,0,65,0,65,0,65,0,0,52,65,65,\n871,65,0,0,65,0,52,65,0,0,52,65,65,\n1001,65,0,0,0,65,52,65,0,0,52,0,0,\n871,0,65,65,65,65,52,65,0,0,52,0,0,\n923,65,65,0,0,0,0,0,65,0,52,65,65,\n988,0,65,65,65,0,0,0,65,0,52,0,0,\n1066,0,0,0,0,0,52,0,65,0,52,65,0,\n806,65,65,0,65,65,52,0,65,0,52,0,65,\n858,65,65,65,0,0,0,65,65,0,52,0,65,\n858,0,0,65,65,0,0,65,65,0,52,65,65,\n858,65,65,0,0,65,0,65,65,0,52,65,0,\n793,65,0,0,65,65,0,65,65,0,52,65,65,\n871,65,65,0,65,0,52,65,65,0,52,0,0,\n741,65,65,65,65,0,52,65,65,0,52,65,0,\n871,0,0,65,0,65,52,65,65,0,52,0,65,\n988,65,0,65,0,0,0,0,0,65,52,65,0,\n988,0,65,0,65,0,0,0,0,65,52,65,0,\n858,0,65,65,0,65,0,0,0,65,52,65,65,\n1001,65,0,0,0,0,52,0,0,65,52,0,65,\n806,65,65,0,0,65,52,0,0,65,52,65,65,\n871,65,0,65,65,65,52,0,0,65,52,0,0,\n858,65,65,0,65,65,0,65,0,65,52,0,0,\n858,0,0,65,65,65,0,65,0,65,52,65,0,\n1001,0,0,0,0,0,52,65,0,65,52,65,0,\n806,0,65,65,65,0,52,65,0,65,52,0,65,\n871,0,0,0,0,65,52,65,0,65,52,65,65,\n988,0,0,65,0,0,0,0,65,65,52,0,65,\n858,65,65,65,0,65,0,0,65,65,52,0,0,\n793,0,65,0,65,65,0,0,65,65,52,65,65,\n793,65,0,65,65,65,0,0,65,65,52,0,65,\n806,0,65,65,0,0,52,0,65,65,52,65,65,\n806,65,0,0,65,65,52,0,65,65,52,65,0,\n806,0,65,65,65,65,52,0,65,65,52,0,0,\n663,65,65,65,65,0,0,65,65,65,52,65,65,\n858,65,0,0,0,65,0,65,65,65,52,0,65,\n728,0,65,65,65,65,0,65,65,65,52,0,65,\n871,0,65,0,0,0,52,65,65,65,52,0,65,\n936,0,0,0,65,0,52,65,65,65,52,0,0,\n923,32.5,32.5,32.5,32.5,32.5,26,32.5,32.5,32.5,26,32.5,32.5,\n923,32.5,32.5,32.5,32.5,32.5,26,32.5,32.5,32.5,26,32.5,32.5,\n1300,0,0,0,0,0,0,0,0,0,0,0,0,\n1300,0,0,0,0,0,0,0,0,0,0,0,0,\n", - "label": "factor .csv file", - "name": "csv_factors", - "type": "textFile" - }, - { - "default": "48.0,48.0,0,0,0,0", - "label": "media tube A1 volume (,-separated, in mL, A1,A2,A3,B1,B2,B3)", - "name": "vol_media_tubes", - "type": "str" - }, - { - "default": 800.0, - "label": "final mix volume (in uL)", - "name": "vol_mix", - "type": "float" - }, - { - "default": 3, - "label": "final mix repetitions", - "name": "reps_mix", - "type": "int" - }, - { - "label": "smaller pipette type", - "name": "type_pipette_small", - "options": [ - { - "label": "P300 (20-200ul)", - "value": "p300_single_gen2" - }, - { - "label": "P20 (1-20ul)", - "value": "p20_single_gen2" - } - ], - "type": "dropDown" - } - ], - "instruments": [ - { - "mount": "left", - "name": "p300_single_gen2" - }, - { - "mount": "right", - "name": "p1000_single_gen2" - } - ], - "labware": [ - { - "name": "media tuberack on 1", - "share": false, - "slot": "1", - "type": "opentrons_6_tuberack_falcon_50ml_conical" - }, - { - "name": "USA Scientific 96 Deep Well Plate 2.4 mL on 2", - "share": false, - "slot": "2", - "type": "usascientific_96_wellplate_2.4ml_deep" - }, - { - "name": "Opentrons 96 Filter Tip Rack 200 \u00b5L on 3", - "share": false, - "slot": "3", - "type": "opentrons_96_filtertiprack_200ul" - }, - { - "name": "factors 1-15 on 4", - "share": false, - "slot": "4", - "type": "opentrons_15_tuberack_falcon_15ml_conical" - }, - { - "name": "factors 31-54 on 5", - "share": false, - "slot": "5", - "type": "opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap" - }, - { - "name": "Opentrons 96 Filter Tip Rack 1000 \u00b5L on 6", - "share": false, - "slot": "6", - "type": "opentrons_96_filtertiprack_1000ul" - }, - { - "name": "factors 16-30 on 7", - "share": false, - "slot": "7", - "type": "opentrons_15_tuberack_falcon_15ml_conical" - }, + "content": "import math\nfrom opentrons.protocol_api.labware import Well\nfrom opentrons.protocols.api_support.types import APIVersion\nfrom opentrons.types import Point\n\nmetadata = {\n 'protocolName': 'DOE',\n 'author': 'Nick self.min_height:\n self.height = self.height - dh\n else:\n self.height = self.min_height\n if self.current_volume - vol > 0:\n self.current_volume = self.current_volume - vol\n else:\n self.current_volume = 0\n return self.well.bottom(self.height)\n\n def height_inc(self, vol):\n dh = (vol/(math.pi*(self.radius**2)))*self.comp_coeff\n if self.height + dh < self.depth:\n self.height = self.height + dh\n else:\n self.height = self.depth\n self.current_volume += vol\n return self.well.bottom(self.height + 20)\n\n # labware\n tuberack50 = ctx.load_labware('opentrons_6_tuberack_falcon_50ml_conical',\n '1', 'media tuberack')\n tuberacks15 = [\n ctx.load_labware(\n 'opentrons_15_tuberack_falcon_15ml_conical', slot,\n f'factors {tube_set}')\n for i, (slot, tube_set) in enumerate(\n zip(['4', '7'], ['1-15', '16-30']))]\n tuberacks2 = [\n ctx.load_labware(\n 'opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap', slot,\n f'factors {tube_set}')\n for i, (slot, tube_set) in enumerate(\n zip(['5', '8'], ['31-54', '55-78']))]\n plate = ctx.load_labware('usascientific_96_wellplate_2.4ml_deep', '2')\n tiprack_small = [ctx.load_labware(tiprack_small_type, '3')]\n tiprack1000 = [\n ctx.load_labware('opentrons_96_filtertiprack_1000ul', slot)\n for slot in ['6']]\n\n # pipettes\n pip_small = ctx.load_instrument(type_pipette_small, 'left',\n tip_racks=tiprack_small)\n p1000 = ctx.load_instrument('p1000_single_gen2', 'right',\n tip_racks=tiprack1000)\n\n # reagents\n vol_media_list = [float(val) for val in vol_media_tubes.split(',')]\n media_rows_ordered = [tube for row in tuberack50.rows() for tube in row]\n media = [\n WellH(well, current_volume=vol, height=well.depth*(vol/50000)*0.9)\n for well, vol in zip(\n media_rows_ordered[:len(vol_media_list)],\n [vol_media_tube*1000 for vol_media_tube in vol_media_list])]\n\n # parse data\n factor_data = [\n [float(val) for val in line.split(',')[1:] if val.strip()]\n for line in csv_factors.splitlines()[3:]\n ]\n\n all_factor_tubes = [\n well for rack_set in [tuberacks15, tuberacks2]\n for rack in rack_set\n for well in rack.wells()]\n\n factor_indices = [\n int(cell.strip().split(' ')[-1]) - 1\n for cell in csv_factors.splitlines()[0].split(',')[1:]\n if cell.strip()]\n factor_tubes = [\n all_factor_tubes[ind] for ind in factor_indices]\n factor_viscosities = [\n bool(visc) for visc in csv_factors.splitlines()[1].split(',')[1:]\n if visc.strip()]\n factor_volumes_ul = [\n float(cell)*1000 for cell in csv_factors.splitlines()[2].split(',')[1:]\n if cell.strip()]\n # ref_vol = tuberacks15[0].wells()[0].max_volume / 1000 # 2ml or 15ml\n # ref_height = tuberacks15[0].wells()[0].depth\n factor_heights = [\n # ensure tip is submerged\n round(factor_vol/(factor_tube.max_volume)*factor_tube.depth*0.9,\n 1)\n for factor_tube, factor_vol in zip(factor_tubes, factor_volumes_ul)]\n factors = [\n WellH(well, current_volume=vol, height=height)\n for well, vol, height in zip(\n factor_tubes, factor_volumes_ul, factor_heights)]\n\n def slow_withdraw(well, pip=p1000, delay_s=2.0):\n ctx.max_speeds['A'] = 25\n ctx.max_speeds['Z'] = 25\n if delay_s > 0:\n ctx.delay(seconds=delay_s)\n pip.move_to(well.top())\n del ctx.max_speeds['A']\n del ctx.max_speeds['Z']\n\n def split_media_vol(vol):\n num_transfers = math.ceil(vol/(1000-vol_pre_airgap_1000))\n vol_per_transfer = round(vol/num_transfers, 1)\n return [vol_per_transfer]*num_transfers\n\n # iterate\n iterator_media = iter(media)\n current_media = next(iterator_media)\n\n def check_media(vol):\n nonlocal current_media\n if current_media.current_volume - vol < current_media.min_vol:\n current_media = next(iterator_media)\n\n def custom_distribute(info, pip):\n pip_volume = pip.tip_racks[0].wells()[0].max_volume\n vol_pre_airgap = vol_pre_airgap_small if pip == \\\n pip_small else vol_pre_airgap_1000\n max_vol = pip_volume\n sets = []\n running = []\n current_vol = 0\n for d in info:\n well = [key for key in d.keys()][0]\n vol = [val for val in d.values()][0]\n if vol > 0:\n if current_vol + vol + vol_pre_airgap > max_vol:\n sets.append(running)\n running = []\n current_vol = 0\n running.append({well: vol})\n current_vol += vol + vol_pre_airgap\n sets.append(running)\n return sets\n\n # transfer media\n p1000.pick_up_tip()\n wells_ordered = [well for row in plate.rows() for well in row]\n vols_media = [\n float(line.split(',')[0]) for line in csv_factors.splitlines()[3:]]\n media_info = []\n for well, vol_media in zip(wells_ordered, vols_media):\n vols_split = split_media_vol(vol_media)\n for vol in vols_split:\n media_info.append({well: vol})\n\n wells_h = [\n WellH(well, height=0) for well in wells_ordered]\n\n for d in media_info:\n well = list(d.keys())[0]\n asp_vol = list(d.values())[0]\n if p1000.current_volume:\n p1000.dispense(p1000.current_volume, current_media.well.top())\n check_media(asp_vol)\n p1000.aspirate(vol_pre_airgap_1000, current_media.well.top())\n p1000.aspirate(asp_vol, current_media.height_dec(asp_vol))\n slow_withdraw(current_media.well, p1000)\n p1000.dispense(p1000.current_volume, well.bottom(well.depth/2))\n p1000.blow_out(well.bottom(well.depth/2))\n slow_withdraw(well, p1000)\n\n # media_sets = custom_distribute(media_info, pip=p1000)\n # for media_set in media_sets:\n # if p1000.current_volume:\n # p1000.dispense(p1000.current_volume, current_media.well.top())\n # # pre-air_gap to fully void tip on blow_out\n # for d in media_set:\n # asp_vol = sum(d.values())\n # check_media(asp_vol)\n # p1000.aspirate(vol_pre_airgap_1000, current_media.well.top())\n # p1000.aspirate(asp_vol, current_media.height_dec(asp_vol))\n # slow_withdraw(current_media.well, p1000)\n # for i, d in enumerate(media_set):\n # well = [key for key in d.keys()][0]\n # vol = [val for val in d.values()][0]\n # p1000.dispense(vol+vol_pre_airgap_1000,\n # well.bottom(well.depth/2))\n # if i == len(media_set) - 1:\n # p1000.blow_out(well.bottom(well.depth/2))\n # slow_withdraw(well, p1000)\n p1000.return_tip()\n p1000.reset_tipracks()\n\n viscosity_map = {\n 20: {\n 'aspirate': 6.5,\n 'delay_aspiration': 2.0,\n 'dispense': 6.5,\n 'delay_dispense': 2.0,\n 'default': 7.56\n },\n 300: {\n 'aspirate': 80,\n 'delay_aspiration': 2.0,\n 'dispense': 80,\n 'delay_dispense': 2.0,\n 'default': 92.86\n },\n 1000: {\n 'aspirate': 247,\n 'delay_aspiration': 2.0,\n 'dispense': 247,\n 'delay_dispense': 2.0,\n 'default': 247\n }\n }\n\n # transfer factors\n for i, (visc, factor) in enumerate(zip(factor_viscosities, factors)):\n factor_vols = [line[i] for line in factor_data]\n factor_info = [\n {well: vol}\n for well, vol in zip(wells_h, factor_vols)]\n factor_sets = custom_distribute(factor_info, pip=pip_small)\n if visc:\n asp_rate_relative = viscosity_map[\n int(pip_small.max_volume)]['aspirate'] / (\n viscosity_map[int(pip_small.max_volume)]['default'])\n asp_delay = viscosity_map[\n int(pip_small.max_volume)]['delay_aspiration']\n disp_rate_relative = viscosity_map[\n int(pip_small.max_volume)]['dispense'] / (\n viscosity_map[int(pip_small.max_volume)]['default'])\n disp_delay = viscosity_map[\n int(pip_small.max_volume)]['delay_dispense']\n else:\n asp_rate_relative = 1\n asp_delay = 2.0\n disp_rate_relative = 1\n disp_delay = 2.0\n for factor_set in factor_sets:\n # aspirate total vol needed\n if not pip_small.has_tip:\n pip_small.pick_up_tip()\n # pre-air_gap to fully void tip on blow_out\n for d in factor_set:\n well = [k for k in d.keys()][0]\n asp_vol = [k for k in d.values()][0]\n if asp_vol + vol_pre_airgap_small <= pip_small.max_volume:\n ag_vol = vol_pre_airgap_small\n else:\n ag_vol = pip_small.max_volume - asp_vol\n pip_small.aspirate(ag_vol, factor.well.top())\n pip_small.aspirate(\n asp_vol, factor.height_dec(asp_vol),\n rate=asp_rate_relative)\n slow_withdraw(factor.well, pip_small, delay_s=asp_delay)\n pip_small.dispense(\n pip_small.current_volume,\n well.height_inc(asp_vol).move(Point(z=3)),\n rate=disp_rate_relative)\n ctx.delay(seconds=disp_delay)\n pip_small.blow_out(well.top(-2))\n\n # total_factor_vol = sum([sum(dict.values()) for dict in\n # factor_set])\n # p300.aspirate(total_factor_vol,\n # factor.height_dec(total_factor_vol))\n # for i, dict in enumerate(factor_set):\n # for well, vol in dict.items():\n # pip_small.dispense(\n # vol+vol_pre_airgap_small, well.bottom(well.depth/2))\n # if i == len(factor_set) - 1:\n # pip_small.blow_out(well.top(-2))\n\n # for d in factor_set:\n # asp_vol = sum(d.values())\n # if asp_vol + vol_pre_airgap_small <= pip_small.max_volume:\n # ag_vol = vol_pre_airgap_small\n # else:\n # ag_vol = pip_small.max_volume - asp_vol\n # pip_small.aspirate(ag_vol, factor.well.top())\n # pip_small.aspirate(asp_vol, factor.height_dec(asp_vol))\n # # total_factor_vol = sum([sum(dict.values()) for dict in\n # # factor_set])\n # # p300.aspirate(total_factor_vol,\n # # factor.height_dec(total_factor_vol))\n # slow_withdraw(factor.well, pip_small)\n # for i, dict in enumerate(factor_set):\n # for well, vol in dict.items():\n # pip_small.dispense(\n # vol+vol_pre_airgap_small, well.bottom(well.depth/2))\n # if i == len(factor_set) - 1:\n # pip_small.blow_out(well.top(-2))\n if pip_small.has_tip:\n pip_small.drop_tip()\n\n # mix\n for well in plate.wells()[:len(factor_data)]:\n p1000.pick_up_tip()\n p1000.mix(reps_mix, vol_mix, well.bottom(2))\n slow_withdraw(well, p1000)\n p1000.drop_tip()\n", + "custom_labware_defs": [], + "fields": [ + { + "default": "Media Total,Factor 1,Factor 2,Factor 3,Factor 4,Factor 5,Factor 6,Factor 7,Factor 8,Factor 9,Factor 10,Factor 11,Factor 12,\nfactor_volumes (in ml):,5,1.5,7,14,10.1,5,1.5,7,14,10.1,2,2,\n1170,0,0,0,0,0,0,0,0,0,0,65,65,\n1235,0,65,0,0,0,0,0,0,0,0,0,0,\n1040,65,65,0,65,0,0,0,0,0,0,0,65,\n975,0,65,65,65,65,0,0,0,0,0,0,65,\n1053,0,0,65,65,0,52,0,0,0,0,65,0,\n988,0,65,65,0,65,52,0,0,0,0,65,0,\n845,65,65,65,65,0,0,65,0,0,0,65,65,\n910,0,65,0,65,65,0,65,0,0,0,65,65,\n858,65,65,65,0,65,52,65,0,0,0,0,65,\n988,0,0,0,65,65,52,65,0,0,0,0,65,\n1040,0,65,65,0,0,0,0,65,0,0,65,0,\n1105,0,0,0,65,0,0,0,65,0,0,0,65,\n1040,65,0,0,0,65,0,0,65,0,0,0,65,\n923,65,0,65,0,0,52,0,65,0,0,65,65,\n923,0,65,0,65,65,52,0,65,0,0,65,0,\n923,65,0,65,65,65,52,0,65,0,0,0,0,\n975,65,0,0,65,0,0,65,65,0,0,65,0,\n1040,0,0,0,0,65,0,65,65,0,0,65,0,\n910,65,65,65,0,65,0,65,65,0,0,0,0,\n1053,0,0,65,0,0,52,65,65,0,0,0,0,\n858,0,65,65,65,0,52,65,65,0,0,0,65,\n793,65,65,0,0,65,52,65,65,0,0,65,65,\n793,0,0,65,65,65,52,65,65,0,0,65,65,\n975,65,65,65,0,0,0,0,0,65,0,0,65,\n1040,65,0,65,65,0,0,0,0,65,0,0,0,\n910,65,0,0,65,65,0,0,0,65,0,65,65,\n1053,0,65,0,0,0,52,0,0,65,0,0,65,\n728,65,65,65,65,65,52,0,0,65,0,65,65,\n1040,0,0,0,65,0,0,65,0,65,0,0,65,\n910,65,65,0,0,65,0,65,0,65,0,65,0,\n1040,0,0,65,0,65,0,65,0,65,0,0,0,\n858,65,0,65,0,0,52,65,0,65,0,65,65,\n923,65,65,0,65,0,52,65,0,65,0,0,0,\n1105,65,0,0,0,0,0,0,65,65,0,0,0,\n910,65,65,0,65,65,0,0,65,65,0,0,0,\n910,0,0,65,65,65,0,0,65,65,0,65,0,\n923,65,65,0,0,0,52,0,65,65,0,65,0,\n923,0,0,0,0,65,52,0,65,65,0,65,65,\n793,65,65,65,0,65,52,0,65,65,0,0,65,\n910,0,65,65,65,0,0,65,65,65,0,0,0,\n780,0,65,65,0,65,0,65,65,65,0,65,65,\n793,0,65,0,65,0,52,65,65,65,0,65,65,\n793,65,0,65,65,0,52,65,65,65,0,0,65,\n923,0,65,0,0,65,52,65,65,65,0,0,0,\n793,65,0,65,0,65,52,65,65,65,0,65,0,\n1118,0,0,65,0,0,0,0,0,0,52,0,65,\n1118,0,0,0,65,65,0,0,0,0,52,0,0,\n858,65,65,65,65,65,0,0,0,0,52,65,0,\n1001,65,65,65,0,0,52,0,0,0,52,0,0,\n936,0,65,0,65,0,52,0,0,0,52,65,65,\n871,0,0,65,65,65,52,0,0,0,52,65,65,\n988,0,65,65,0,0,0,65,0,0,52,65,0,\n988,65,0,65,65,0,0,65,0,0,52,0,0,\n988,0,65,0,0,65,0,65,0,0,52,0,65,\n858,65,0,65,0,65,0,65,0,0,52,65,65,\n871,65,0,0,65,0,52,65,0,0,52,65,65,\n1001,65,0,0,0,65,52,65,0,0,52,0,0,\n871,0,65,65,65,65,52,65,0,0,52,0,0,\n923,65,65,0,0,0,0,0,65,0,52,65,65,\n988,0,65,65,65,0,0,0,65,0,52,0,0,\n1066,0,0,0,0,0,52,0,65,0,52,65,0,\n806,65,65,0,65,65,52,0,65,0,52,0,65,\n858,65,65,65,0,0,0,65,65,0,52,0,65,\n858,0,0,65,65,0,0,65,65,0,52,65,65,\n858,65,65,0,0,65,0,65,65,0,52,65,0,\n793,65,0,0,65,65,0,65,65,0,52,65,65,\n871,65,65,0,65,0,52,65,65,0,52,0,0,\n741,65,65,65,65,0,52,65,65,0,52,65,0,\n871,0,0,65,0,65,52,65,65,0,52,0,65,\n988,65,0,65,0,0,0,0,0,65,52,65,0,\n988,0,65,0,65,0,0,0,0,65,52,65,0,\n858,0,65,65,0,65,0,0,0,65,52,65,65,\n1001,65,0,0,0,0,52,0,0,65,52,0,65,\n806,65,65,0,0,65,52,0,0,65,52,65,65,\n871,65,0,65,65,65,52,0,0,65,52,0,0,\n858,65,65,0,65,65,0,65,0,65,52,0,0,\n858,0,0,65,65,65,0,65,0,65,52,65,0,\n1001,0,0,0,0,0,52,65,0,65,52,65,0,\n806,0,65,65,65,0,52,65,0,65,52,0,65,\n871,0,0,0,0,65,52,65,0,65,52,65,65,\n988,0,0,65,0,0,0,0,65,65,52,0,65,\n858,65,65,65,0,65,0,0,65,65,52,0,0,\n793,0,65,0,65,65,0,0,65,65,52,65,65,\n793,65,0,65,65,65,0,0,65,65,52,0,65,\n806,0,65,65,0,0,52,0,65,65,52,65,65,\n806,65,0,0,65,65,52,0,65,65,52,65,0,\n806,0,65,65,65,65,52,0,65,65,52,0,0,\n663,65,65,65,65,0,0,65,65,65,52,65,65,\n858,65,0,0,0,65,0,65,65,65,52,0,65,\n728,0,65,65,65,65,0,65,65,65,52,0,65,\n871,0,65,0,0,0,52,65,65,65,52,0,65,\n936,0,0,0,65,0,52,65,65,65,52,0,0,\n923,32.5,32.5,32.5,32.5,32.5,26,32.5,32.5,32.5,26,32.5,32.5,\n923,32.5,32.5,32.5,32.5,32.5,26,32.5,32.5,32.5,26,32.5,32.5,\n1300,0,0,0,0,0,0,0,0,0,0,0,0,\n1300,0,0,0,0,0,0,0,0,0,0,0,0,\n", + "label": "factor .csv file", + "name": "csv_factors", + "type": "textFile" + }, + { + "default": "48.0,48.0,0,0,0,0", + "label": "media tube A1 volume (,-separated, in mL, A1,A2,A3,B1,B2,B3)", + "name": "vol_media_tubes", + "type": "str" + }, + { + "default": 800.0, + "label": "final mix volume (in uL)", + "name": "vol_mix", + "type": "float" + }, + { + "default": 3, + "label": "final mix repetitions", + "name": "reps_mix", + "type": "int" + }, + { + "label": "smaller pipette type", + "name": "type_pipette_small", + "options": [ { - "name": "factors 55-78 on 8", - "share": false, - "slot": "8", - "type": "opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap" + "label": "P300 (20-200ul)", + "value": "p300_single_gen2" }, { - "name": "Opentrons Fixed Trash on 12", - "share": false, - "slot": "12", - "type": "opentrons_1_trash_1100ml_fixed" + "label": "P20 (1-20ul)", + "value": "p20_single_gen2" } - ], - "metadata": { - "apiLevel": "2.12", - "author": "Nick