Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -220,16 +220,14 @@ mockPythonName.drop_tip()
// Step c:
`
mockPythonName.pick_up_tip(location=mockPythonName)
mockPythonName.aspirate(...)
mockPythonName.dispense(...)
mockPythonName.aspirate(...)
mockPythonName.dispense(...)
mockPythonName.flow_rate.aspirate = 3.78
mockPythonName.flow_rate.dispense = 3.78
mockPythonName.mix(...)
mockPythonName.drop_tip()
mockPythonName.pick_up_tip(location=mockPythonName)
mockPythonName.aspirate(...)
mockPythonName.dispense(...)
mockPythonName.aspirate(...)
mockPythonName.dispense(...)
mockPythonName.flow_rate.aspirate = 3.78
mockPythonName.flow_rate.dispense = 3.78
mockPythonName.mix(...)
mockPythonName.drop_tip()
`.trim(),
])
Expand Down
93 changes: 26 additions & 67 deletions step-generation/src/__tests__/mix.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ describe('mix: advanced options', () => {
changeTip: 'always',
wells: ['A1', 'B1', 'C1'],
yOffset: 1,
finalPushOut: 2,
} as MixArgs
const mockWellLocationCustomXY: Partial<AspDispAirgapParams> = {
wellLocation: {
Expand All @@ -371,7 +372,10 @@ describe('mix: advanced options', () => {
delayCommand(12),
aspirateHelper(well, volume, mockWellLocationCustomXY),
delayCommand(10),
dispenseHelper(well, volume, mockWellLocationCustomXY),
dispenseHelper(well, volume, {
...mockWellLocationCustomXY,
pushOut: 2,
}),
delayCommand(12),
blowoutHelper(blowoutLabwareId, {
wellLocation: {
Expand All @@ -388,91 +392,46 @@ describe('mix: advanced options', () => {
`
mockPythonName.drop_tip()
mockPythonName.pick_up_tip(location=mockPythonName)
mockPythonName.aspirate(
volume=8,
location=mockPythonName["A1"].bottom(z=3.2).move(types.Point(y=1)),
rate=2.1 / mockPythonName.flow_rate.aspirate,
)
protocol.delay(seconds=10)
mockPythonName.dispense(
volume=8,
location=mockPythonName["A1"].bottom(z=3.2).move(types.Point(y=1)),
rate=2.2 / mockPythonName.flow_rate.dispense,
push_out=0,
)
protocol.delay(seconds=12)
mockPythonName.aspirate(
volume=8,
location=mockPythonName["A1"].bottom(z=3.2).move(types.Point(y=1)),
rate=2.1 / mockPythonName.flow_rate.aspirate,
)
protocol.delay(seconds=10)
mockPythonName.dispense(
mockPythonName.flow_rate.aspirate = 2.1
mockPythonName.flow_rate.dispense = 2.2
mockPythonName.mix(
repetitions=2,
volume=8,
location=mockPythonName["A1"].bottom(z=3.2).move(types.Point(y=1)),
rate=2.2 / mockPythonName.flow_rate.dispense,
aspirate_delay=10,
dispense_delay=12,
final_push_out=2,
)
protocol.delay(seconds=12)
mockPythonName.flow_rate.blow_out = 2.3
mockPythonName.blow_out(mockPythonName["A1"].top(z=3.3))
mockPythonName.touch_tip(mockPythonName["A1"], v_offset=-3.4)
mockPythonName.drop_tip()
mockPythonName.pick_up_tip(location=mockPythonName)
mockPythonName.aspirate(
volume=8,
location=mockPythonName["B1"].bottom(z=3.2).move(types.Point(y=1)),
rate=2.1 / mockPythonName.flow_rate.aspirate,
)
protocol.delay(seconds=10)
mockPythonName.dispense(
volume=8,
location=mockPythonName["B1"].bottom(z=3.2).move(types.Point(y=1)),
rate=2.2 / mockPythonName.flow_rate.dispense,
push_out=0,
)
protocol.delay(seconds=12)
mockPythonName.aspirate(
volume=8,
location=mockPythonName["B1"].bottom(z=3.2).move(types.Point(y=1)),
rate=2.1 / mockPythonName.flow_rate.aspirate,
)
protocol.delay(seconds=10)
mockPythonName.dispense(
mockPythonName.flow_rate.aspirate = 2.1
mockPythonName.flow_rate.dispense = 2.2
mockPythonName.mix(
repetitions=2,
volume=8,
location=mockPythonName["B1"].bottom(z=3.2).move(types.Point(y=1)),
rate=2.2 / mockPythonName.flow_rate.dispense,
aspirate_delay=10,
dispense_delay=12,
final_push_out=2,
)
protocol.delay(seconds=12)
mockPythonName.flow_rate.blow_out = 2.3
mockPythonName.blow_out(mockPythonName["A1"].top(z=3.3))
mockPythonName.touch_tip(mockPythonName["B1"], v_offset=-3.4)
mockPythonName.drop_tip()
mockPythonName.pick_up_tip(location=mockPythonName)
mockPythonName.aspirate(
volume=8,
location=mockPythonName["C1"].bottom(z=3.2).move(types.Point(y=1)),
rate=2.1 / mockPythonName.flow_rate.aspirate,
)
protocol.delay(seconds=10)
mockPythonName.dispense(
volume=8,
location=mockPythonName["C1"].bottom(z=3.2).move(types.Point(y=1)),
rate=2.2 / mockPythonName.flow_rate.dispense,
push_out=0,
)
protocol.delay(seconds=12)
mockPythonName.aspirate(
volume=8,
location=mockPythonName["C1"].bottom(z=3.2).move(types.Point(y=1)),
rate=2.1 / mockPythonName.flow_rate.aspirate,
)
protocol.delay(seconds=10)
mockPythonName.dispense(
mockPythonName.flow_rate.aspirate = 2.1
mockPythonName.flow_rate.dispense = 2.2
mockPythonName.mix(
repetitions=2,
volume=8,
location=mockPythonName["C1"].bottom(z=3.2).move(types.Point(y=1)),
rate=2.2 / mockPythonName.flow_rate.dispense,
aspirate_delay=10,
dispense_delay=12,
final_push_out=2,
)
protocol.delay(seconds=12)
mockPythonName.flow_rate.blow_out = 2.3
mockPythonName.blow_out(mockPythonName["A1"].top(z=3.3))
mockPythonName.touch_tip(mockPythonName["C1"], v_offset=-3.4)`.trimStart()
Expand Down
30 changes: 11 additions & 19 deletions step-generation/src/commandCreators/compound/mix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,21 +74,11 @@ export function mixUtil(args: {
invariantContext,
finalPushOut,
} = args
// If delay is specified to something other than 0,
// emit individual py commands. Otherwise, emit mix()
const hasUnsupportedMixApiArg =
(aspirateDelaySeconds != null && aspirateDelaySeconds !== 0) ||
(dispenseDelaySeconds != null && dispenseDelaySeconds !== 0) ||
finalPushOut != null

const curryCreator = hasUnsupportedMixApiArg
? curryCommandCreator
: curryWithoutPython

const getDelayCommand = (seconds?: number | null): CurriedCommandCreator[] =>
seconds
? [
curryCreator(delay, {
curryWithoutPython(delay, {
seconds,
}),
]
Expand All @@ -108,8 +98,13 @@ export function mixUtil(args: {
`location=${labwarePythonName}[${formatPyStr(
well
)}]${formatPyWellLocation(pythonWellLocation)}`,
// TODO (nd, 04/09/2025): uncomment next line once PAPI supports new `final_push_out` arg
// `final_push_out=${finalPushOut}`
...(aspirateDelaySeconds != null && aspirateDelaySeconds !== 0
? [`aspirate_delay=${aspirateDelaySeconds}`]
: []),
...(dispenseDelaySeconds != null && dispenseDelaySeconds !== 0
? [`dispense_delay=${dispenseDelaySeconds}`]
: []),
...(finalPushOut != null ? [`final_push_out=${finalPushOut}`] : []),
]
return {
commands: [],
Expand All @@ -128,7 +123,7 @@ export function mixUtil(args: {
for (let i = 0; i < times; i++) {
commandCreators.push(
...[
curryCreator(aspirate, {
curryWithoutPython(aspirate, {
pipetteId: pipette,
volume,
labwareId: labware,
Expand All @@ -146,7 +141,7 @@ export function mixUtil(args: {
nozzles: null,
}),
...getDelayCommand(aspirateDelaySeconds),
curryCreator(dispense, {
curryWithoutPython(dispense, {
pipetteId: pipette,
volume,
labwareId: labware,
Expand All @@ -172,10 +167,7 @@ export function mixUtil(args: {
]
)
}
return [
...commandCreators,
...(hasUnsupportedMixApiArg ? [] : [pythonCommandCreator]),
]
return [...commandCreators, pythonCommandCreator]
}
export const mix: CommandCreator<MixArgs> = (
data,
Expand Down
Loading