-
Notifications
You must be signed in to change notification settings - Fork 171
/
dispenseUpdateLiquidState.js
112 lines (102 loc) · 3.06 KB
/
dispenseUpdateLiquidState.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// @flow
import assert from 'assert'
import mapValues from 'lodash/mapValues'
import reduce from 'lodash/reduce'
import {
splitLiquid,
mergeLiquid,
getWellsForTips,
getLocationTotalVolume,
} from '../utils/misc'
import type {
RobotState,
InvariantContext,
LocationLiquidState,
SourceAndDest,
} from '../types'
type LiquidState = $PropertyType<RobotState, 'liquidState'>
type DispenseUpdateLiquidStateArgs = {|
invariantContext: InvariantContext,
prevLiquidState: LiquidState,
labware: string,
pipette: string,
well: string,
volume?: number, // volume value is required when useFullVolume is false
useFullVolume: boolean,
|}
/** This is a helper to do dispense/blowout liquid state updates. */
export function dispenseUpdateLiquidState(
args: DispenseUpdateLiquidStateArgs
): void {
const {
invariantContext,
labware,
pipette,
prevLiquidState,
useFullVolume,
volume,
well,
} = args
const pipetteSpec = invariantContext.pipetteEntities[pipette].spec
const labwareDef = invariantContext.labwareEntities[labware].def
assert(
!(useFullVolume && typeof volume === 'number'),
'dispenseUpdateLiquidState takes either `volume` or `useFullVolume`, but got both'
)
assert(
typeof volume === 'number' || useFullVolume,
'in dispenseUpdateLiquidState, either volume or useFullVolume are required'
)
const { wellsForTips, allWellsShared } = getWellsForTips(
pipetteSpec.channels,
labwareDef,
well
)
const liquidLabware = prevLiquidState.labware[labware]
// remove liquid from pipette tips,
// create intermediate object where sources are updated tip liquid states
// and dests are "droplets" that need to be merged to dest well contents
const splitLiquidStates: { [tipId: string]: SourceAndDest } = mapValues(
prevLiquidState.pipettes[pipette],
(prevTipLiquidState: LocationLiquidState): SourceAndDest => {
if (useFullVolume) {
const totalTipVolume = getLocationTotalVolume(prevTipLiquidState)
return totalTipVolume > 0
? splitLiquid(totalTipVolume, prevTipLiquidState)
: { source: null, dest: null }
}
return splitLiquid(volume || 0, prevTipLiquidState)
}
)
const mergeLiquidtoSingleWell = {
[well]: reduce(
splitLiquidStates,
(wellLiquidStateAcc, splitLiquidStateForTip: SourceAndDest) => {
const res = mergeLiquid(wellLiquidStateAcc, splitLiquidStateForTip.dest)
return res
},
liquidLabware[well]
),
}
const mergeTipLiquidToOwnWell = wellsForTips.reduce(
(acc, wellForTip, tipIdx) => {
return {
...acc,
[wellForTip]: mergeLiquid(
splitLiquidStates[`${tipIdx}`].dest,
liquidLabware[wellForTip] || null
),
}
},
{}
)
// add liquid to well(s)
const labwareLiquidState = allWellsShared
? mergeLiquidtoSingleWell
: mergeTipLiquidToOwnWell
prevLiquidState.pipettes[pipette] = mapValues(splitLiquidStates, 'source')
prevLiquidState.labware[labware] = Object.assign(
liquidLabware,
labwareLiquidState
)
}