@opentrons/shared-data 0.0.1-alpha.20 → 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Makefile +1 -1
- package/lib/opentrons-shared-data.js +1 -1
- package/lib/opentrons-shared-data.js.map +1 -1
- package/package.json +1 -1
- package/js/__tests__/__snapshots__/pipettes.test.ts.snap +0 -5969
- package/js/__tests__/deckSchemas.test.ts +0 -87
- package/js/__tests__/errors.test.js +0 -21
- package/js/__tests__/getAreSlotsAdjacent.test.ts +0 -128
- package/js/__tests__/getWellNamePerMultiTip.test.ts +0 -162
- package/js/__tests__/labwareDefQuirks.test.ts +0 -37
- package/js/__tests__/labwareDefSchemaV1.test.ts +0 -82
- package/js/__tests__/labwareDefSchemaV2.test.ts +0 -298
- package/js/__tests__/moduleAccessors.test.ts +0 -50
- package/js/__tests__/moduleSpecsSchema.test.ts +0 -77
- package/js/__tests__/pipetteSchemaV2.test.ts +0 -107
- package/js/__tests__/pipetteSpecSchemas.test.ts +0 -48
- package/js/__tests__/pipettes.test.ts +0 -58
- package/js/__tests__/protocolSchemaV4.test.ts +0 -137
- package/js/__tests__/protocolSchemaV5.test.ts +0 -137
- package/js/__tests__/protocolSchemaV6.test.ts +0 -132
- package/js/__tests__/protocolSchemaV7.test.ts +0 -64
- package/js/__tests__/protocolValidation.test.ts +0 -83
- package/js/__tests__/sortWells.test.ts +0 -40
- package/js/__tests__/splitWellsOnColumn.test.ts +0 -21
- package/js/__tests__/validateErrors.test.js +0 -34
- package/js/constants.ts +0 -338
- package/js/cypressUtils.ts +0 -35
- package/js/errors.ts +0 -33
- package/js/fixtures.ts +0 -161
- package/js/getLabware.ts +0 -154
- package/js/gripper.ts +0 -29
- package/js/helpers/__tests__/getAdapterName.test.ts +0 -31
- package/js/helpers/__tests__/getDeckDefFromLoadedLabware.test.ts +0 -12
- package/js/helpers/__tests__/getVectorDifference.test.ts +0 -25
- package/js/helpers/__tests__/getVectorSum.test.ts +0 -21
- package/js/helpers/__tests__/labwareInference.test.ts +0 -84
- package/js/helpers/__tests__/orderWells.test.ts +0 -87
- package/js/helpers/__tests__/parseProtocolData.test.ts +0 -165
- package/js/helpers/__tests__/volume.test.ts +0 -108
- package/js/helpers/__tests__/wellSets.test.ts +0 -352
- package/js/helpers/get96Channel384WellPlateWells.ts +0 -44
- package/js/helpers/getAddressableAreasInProtocol.ts +0 -59
- package/js/helpers/getLoadedLabwareDefinitionsByUri.ts +0 -30
- package/js/helpers/getModuleVizDims.ts +0 -118
- package/js/helpers/getOccludedSlotCountForModule.ts +0 -13
- package/js/helpers/getVectorDifference.ts +0 -12
- package/js/helpers/getVectorSum.ts +0 -12
- package/js/helpers/getWellNamePerMultiTip.ts +0 -86
- package/js/helpers/getWellTotalVolume.ts +0 -16
- package/js/helpers/index.ts +0 -347
- package/js/helpers/labwareInference.ts +0 -92
- package/js/helpers/orderWells.ts +0 -69
- package/js/helpers/parseProtocolData.ts +0 -141
- package/js/helpers/volume.ts +0 -35
- package/js/helpers/wellIsRect.ts +0 -6
- package/js/helpers/wellSets.ts +0 -155
- package/js/index.ts +0 -14
- package/js/labwareTools/__tests__/__snapshots__/createIrregularLabware.test.ts.snap +0 -3
- package/js/labwareTools/__tests__/__snapshots__/createLabware.test.ts.snap +0 -3
- package/js/labwareTools/__tests__/createDefaultDisplayName.test.ts +0 -111
- package/js/labwareTools/__tests__/createIrregularLabware.test.ts +0 -226
- package/js/labwareTools/__tests__/createLabware.test.ts +0 -147
- package/js/labwareTools/index.ts +0 -452
- package/js/modules.ts +0 -97
- package/js/pipettes.ts +0 -89
- package/js/protocols.ts +0 -290
- package/js/schema.ts +0 -80
- package/js/scripts/generateDeckLayersFromSVG.js +0 -46
- package/js/titleCase.ts +0 -30
- package/js/types.ts +0 -600
- package/python/.coveragerc +0 -4
- package/python/.flake8 +0 -32
- package/python/Config.in +0 -10
- package/python/Makefile +0 -134
- package/python/Pipfile +0 -28
- package/python/Pipfile.lock +0 -645
- package/python/buildroot.mk +0 -30
- package/python/mypy.ini +0 -41
- package/python/opentrons_shared_data/__init__.py +0 -17
- package/python/opentrons_shared_data/_version.py +0 -20
- package/python/opentrons_shared_data/command/__init__.py +0 -52
- package/python/opentrons_shared_data/deck/__init__.py +0 -96
- package/python/opentrons_shared_data/deck/dev_types.py +0 -180
- package/python/opentrons_shared_data/errors/__init__.py +0 -30
- package/python/opentrons_shared_data/errors/categories.py +0 -60
- package/python/opentrons_shared_data/errors/codes.py +0 -108
- package/python/opentrons_shared_data/errors/exceptions.py +0 -915
- package/python/opentrons_shared_data/gripper/__init__.py +0 -63
- package/python/opentrons_shared_data/gripper/constants.py +0 -6
- package/python/opentrons_shared_data/gripper/gripper_definition.py +0 -101
- package/python/opentrons_shared_data/labware/__init__.py +0 -22
- package/python/opentrons_shared_data/labware/constants.py +0 -7
- package/python/opentrons_shared_data/labware/dev_types.py +0 -140
- package/python/opentrons_shared_data/labware/labware_definition.py +0 -328
- package/python/opentrons_shared_data/load.py +0 -57
- package/python/opentrons_shared_data/module/__init__.py +0 -74
- package/python/opentrons_shared_data/module/dev_types.py +0 -141
- package/python/opentrons_shared_data/pipette/__init__.py +0 -107
- package/python/opentrons_shared_data/pipette/dev_types.py +0 -177
- package/python/opentrons_shared_data/pipette/file_operation_helpers.py +0 -37
- package/python/opentrons_shared_data/pipette/load_data.py +0 -261
- package/python/opentrons_shared_data/pipette/model_constants.py +0 -123
- package/python/opentrons_shared_data/pipette/mutable_configurations.py +0 -431
- package/python/opentrons_shared_data/pipette/pipette_definition.py +0 -503
- package/python/opentrons_shared_data/pipette/pipette_load_name_conversions.py +0 -240
- package/python/opentrons_shared_data/pipette/scripts/__init__.py +0 -0
- package/python/opentrons_shared_data/pipette/scripts/build_json_script.py +0 -469
- package/python/opentrons_shared_data/pipette/scripts/update_configuration_files.py +0 -450
- package/python/opentrons_shared_data/pipette/types.py +0 -193
- package/python/opentrons_shared_data/protocol/__init__.py +0 -13
- package/python/opentrons_shared_data/protocol/constants.py +0 -98
- package/python/opentrons_shared_data/protocol/dev_types.py +0 -436
- package/python/opentrons_shared_data/protocol/models/__init__.py +0 -48
- package/python/opentrons_shared_data/protocol/models/protocol_schema_v6.py +0 -145
- package/python/opentrons_shared_data/protocol/models/protocol_schema_v7.py +0 -95
- package/python/opentrons_shared_data/protocol/models/protocol_schema_v8.py +0 -110
- package/python/opentrons_shared_data/protocol/models/shared_models.py +0 -111
- package/python/opentrons_shared_data/py.typed +0 -0
- package/python/opentrons_shared_data/robot/__init__.py +0 -33
- package/python/opentrons_shared_data/robot/dev_types.py +0 -37
- package/python/pytest.ini +0 -2
- package/python/setup.cfg +0 -5
- package/python/setup.py +0 -179
- package/python/tests/__init__.py +0 -1
- package/python/tests/conftest.py +0 -0
- package/python/tests/deck/__init__.py +0 -0
- package/python/tests/deck/test_list_names.py +0 -12
- package/python/tests/deck/test_position.py +0 -113
- package/python/tests/deck/test_typechecks.py +0 -28
- package/python/tests/errors/__init__.py +0 -1
- package/python/tests/errors/test_error_completeness.py +0 -19
- package/python/tests/errors/test_exceptions.py +0 -74
- package/python/tests/gripper/__init__.py +0 -0
- package/python/tests/gripper/test_definition.py +0 -30
- package/python/tests/gripper/test_load.py +0 -16
- package/python/tests/labware/__init__.py +0 -13
- package/python/tests/labware/test_typechecks.py +0 -21
- package/python/tests/module/__init__.py +0 -20
- package/python/tests/module/test_load.py +0 -49
- package/python/tests/module/test_typechecks.py +0 -34
- package/python/tests/pipette/__init__.py +0 -0
- package/python/tests/pipette/test_load_data.py +0 -103
- package/python/tests/pipette/test_mutable_configurations.py +0 -266
- package/python/tests/pipette/test_pipette_definition.py +0 -183
- package/python/tests/pipette/test_pipette_load_name_conversions.py +0 -222
- package/python/tests/pipette/test_typechecks.py +0 -50
- package/python/tests/pipette/test_validate_schema.py +0 -37
- package/python/tests/protocol/__init__.py +0 -15
- package/python/tests/protocol/test_protocol_schema_v6.py +0 -107
- package/python/tests/protocol/test_protocol_schema_v7.py +0 -34
- package/python/tests/protocol/test_protocol_schema_v8.py +0 -20
- package/python/tests/protocol/test_typechecks.py +0 -36
- package/python/tests/robot/__init__.py +0 -0
- package/python/tests/robot/test_typechecks.py +0 -20
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { OT2_ROBOT_TYPE, THERMOCYCLER_MODULE_TYPE } from '..'
|
|
2
|
-
import type { ModuleType, RobotType } from '..'
|
|
3
|
-
|
|
4
|
-
export function getOccludedSlotCountForModule(
|
|
5
|
-
moduleType: ModuleType,
|
|
6
|
-
robotType: RobotType
|
|
7
|
-
): number {
|
|
8
|
-
if (moduleType === THERMOCYCLER_MODULE_TYPE) {
|
|
9
|
-
return robotType === OT2_ROBOT_TYPE ? 4 : 2
|
|
10
|
-
} else {
|
|
11
|
-
return 1
|
|
12
|
-
}
|
|
13
|
-
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import range from 'lodash/range'
|
|
2
|
-
import { get96Channel384WellPlateWells } from './get96Channel384WellPlateWells'
|
|
3
|
-
import { getLabwareHasQuirk, orderWells, sortWells } from './index'
|
|
4
|
-
import type { LabwareDefinition2 } from '../types'
|
|
5
|
-
|
|
6
|
-
// TODO Ian 2018-03-13 pull pipette offsets/positions from some pipette definitions data
|
|
7
|
-
const OFFSET_8_CHANNEL = 9 // offset in mm between tips
|
|
8
|
-
|
|
9
|
-
const MULTICHANNEL_TIP_SPAN = OFFSET_8_CHANNEL * (8 - 1) // length in mm from first to last tip of multichannel
|
|
10
|
-
|
|
11
|
-
export function findWellAt(
|
|
12
|
-
labwareDef: LabwareDefinition2,
|
|
13
|
-
x: number,
|
|
14
|
-
y: number
|
|
15
|
-
): string | null | undefined {
|
|
16
|
-
return Object.keys(labwareDef.wells)
|
|
17
|
-
.sort(sortWells)
|
|
18
|
-
.find((wellName: string) => {
|
|
19
|
-
const well = labwareDef.wells[wellName]
|
|
20
|
-
|
|
21
|
-
if (well.shape === 'circular') {
|
|
22
|
-
return (
|
|
23
|
-
Math.sqrt(Math.pow(x - well.x, 2) + Math.pow(y - well.y, 2)) <
|
|
24
|
-
well.diameter / 2
|
|
25
|
-
)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Not circular, must be a rectangular well
|
|
29
|
-
// For rectangular wells, (x, y) is at the center.
|
|
30
|
-
return (
|
|
31
|
-
Math.abs(x - well.x) < well.xDimension / 2 &&
|
|
32
|
-
Math.abs(y - well.y) < well.yDimension / 2
|
|
33
|
-
)
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// "topWellName" means well at the "top" of the column we're accessing: usually A row, or B row for 384-format
|
|
38
|
-
export function getWellNamePerMultiTip(
|
|
39
|
-
labwareDef: LabwareDefinition2,
|
|
40
|
-
topWellName: string,
|
|
41
|
-
channels: 8 | 96
|
|
42
|
-
): string[] | null {
|
|
43
|
-
const topWell = labwareDef.wells[topWellName]
|
|
44
|
-
if (!topWell) {
|
|
45
|
-
console.warn(
|
|
46
|
-
`well "${topWellName}" does not exist in labware ${labwareDef?.namespace}/${labwareDef?.parameters?.loadName}, cannot getWellNamePerMultiTip`
|
|
47
|
-
)
|
|
48
|
-
return null
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const { x, y } = topWell
|
|
52
|
-
let offsetYTipPositions: number[] = range(0, 8).map(
|
|
53
|
-
tipNo => y - tipNo * OFFSET_8_CHANNEL
|
|
54
|
-
)
|
|
55
|
-
const orderedWells = orderWells(labwareDef.ordering, 't2b', 'l2r')
|
|
56
|
-
|
|
57
|
-
if (getLabwareHasQuirk(labwareDef, 'centerMultichannelOnWells')) {
|
|
58
|
-
// move multichannel up in Y by half the pipette's tip span to center it in the well
|
|
59
|
-
offsetYTipPositions = offsetYTipPositions.map(
|
|
60
|
-
tipPosY => tipPosY + MULTICHANNEL_TIP_SPAN / 2
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
// Return null for containers with any undefined wells
|
|
64
|
-
const wellsAccessed = offsetYTipPositions.reduce(
|
|
65
|
-
(acc: string[] | null, tipPosY) => {
|
|
66
|
-
const wellForTip = findWellAt(labwareDef, x, tipPosY)
|
|
67
|
-
if (acc === null || !wellForTip) {
|
|
68
|
-
return null
|
|
69
|
-
}
|
|
70
|
-
return acc.concat(wellForTip)
|
|
71
|
-
},
|
|
72
|
-
[]
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
let ninetySixChannelWells = orderedWells
|
|
76
|
-
// special casing 384 well plates to be every other well
|
|
77
|
-
// both on the x and y ases.
|
|
78
|
-
if (orderedWells.length === 384) {
|
|
79
|
-
ninetySixChannelWells = get96Channel384WellPlateWells(
|
|
80
|
-
orderedWells,
|
|
81
|
-
topWellName
|
|
82
|
-
)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return channels === 8 ? wellsAccessed : ninetySixChannelWells
|
|
86
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { LabwareDefinition2 } from '../types'
|
|
2
|
-
export const getWellTotalVolume = (
|
|
3
|
-
labwareDef: LabwareDefinition2,
|
|
4
|
-
wellName: string
|
|
5
|
-
): number | null | undefined => {
|
|
6
|
-
const well = labwareDef.wells[wellName]
|
|
7
|
-
|
|
8
|
-
if (!well) {
|
|
9
|
-
console.warn(
|
|
10
|
-
`No well "${wellName}" found for labware ${labwareDef?.namespace}/${labwareDef?.parameters?.loadName}/${labwareDef?.version}"`
|
|
11
|
-
)
|
|
12
|
-
return null
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
return well.totalLiquidVolume
|
|
16
|
-
}
|
package/js/helpers/index.ts
DELETED
|
@@ -1,347 +0,0 @@
|
|
|
1
|
-
import assert from 'assert'
|
|
2
|
-
import uniq from 'lodash/uniq'
|
|
3
|
-
|
|
4
|
-
import { OPENTRONS_LABWARE_NAMESPACE } from '../constants'
|
|
5
|
-
import standardOt2DeckDef from '../../deck/definitions/4/ot2_standard.json'
|
|
6
|
-
import standardFlexDeckDef from '../../deck/definitions/4/ot3_standard.json'
|
|
7
|
-
import type {
|
|
8
|
-
DeckDefinition,
|
|
9
|
-
LabwareDefinition2,
|
|
10
|
-
ModuleModel,
|
|
11
|
-
RobotType,
|
|
12
|
-
ThermalAdapterName,
|
|
13
|
-
} from '../types'
|
|
14
|
-
|
|
15
|
-
export { getWellNamePerMultiTip } from './getWellNamePerMultiTip'
|
|
16
|
-
export { getWellTotalVolume } from './getWellTotalVolume'
|
|
17
|
-
export { wellIsRect } from './wellIsRect'
|
|
18
|
-
export { orderWells } from './orderWells'
|
|
19
|
-
export { get96Channel384WellPlateWells } from './get96Channel384WellPlateWells'
|
|
20
|
-
|
|
21
|
-
export * from './parseProtocolData'
|
|
22
|
-
export * from './volume'
|
|
23
|
-
export * from './wellSets'
|
|
24
|
-
export * from './getModuleVizDims'
|
|
25
|
-
export * from './getVectorDifference'
|
|
26
|
-
export * from './getVectorSum'
|
|
27
|
-
export * from './getLoadedLabwareDefinitionsByUri'
|
|
28
|
-
export * from './getOccludedSlotCountForModule'
|
|
29
|
-
export * from './labwareInference'
|
|
30
|
-
export * from './getAddressableAreasInProtocol'
|
|
31
|
-
|
|
32
|
-
export const getLabwareDefIsStandard = (def: LabwareDefinition2): boolean =>
|
|
33
|
-
def?.namespace === OPENTRONS_LABWARE_NAMESPACE
|
|
34
|
-
|
|
35
|
-
export const getLabwareDefURI = (def: LabwareDefinition2): string =>
|
|
36
|
-
constructLabwareDefURI(
|
|
37
|
-
def.namespace,
|
|
38
|
-
def.parameters.loadName,
|
|
39
|
-
String(def.version)
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
export const constructLabwareDefURI = (
|
|
43
|
-
namespace: string,
|
|
44
|
-
loadName: string,
|
|
45
|
-
version: string
|
|
46
|
-
): string => `${namespace}/${loadName}/${version}`
|
|
47
|
-
|
|
48
|
-
// Load names of "retired" labware
|
|
49
|
-
// TODO(mc, 2019-12-3): how should this correspond to LABWAREV2_DO_NOT_LIST?
|
|
50
|
-
// see shared-data/js/getLabware.js
|
|
51
|
-
const RETIRED_LABWARE = [
|
|
52
|
-
'geb_96_tiprack_10ul',
|
|
53
|
-
'geb_96_tiprack_1000ul',
|
|
54
|
-
'opentrons_1_trash_850ml_fixed',
|
|
55
|
-
'opentrons_10_tuberack_falcon_4x50ml_6x15ml_conical_acrylic',
|
|
56
|
-
'opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap_acrylic',
|
|
57
|
-
'opentrons_24_tuberack_generic_0.75ml_snapcap_acrylic',
|
|
58
|
-
'opentrons_40_aluminumblock_eppendorf_24x2ml_safelock_snapcap_generic_16x0.2ml_pcr_strip',
|
|
59
|
-
'opentrons_96_aluminumblock_biorad_wellplate_200ul',
|
|
60
|
-
'tipone_96_tiprack_200ul',
|
|
61
|
-
'eppendorf_96_tiprack_1000ul_eptips',
|
|
62
|
-
'eppendorf_96_tiprack_10ul_eptips',
|
|
63
|
-
// Replaced by opentrons_96_wellplate_200ul_pcr_full_skirt
|
|
64
|
-
// https://opentrons.atlassian.net/browse/RLAB-230
|
|
65
|
-
'armadillo_96_wellplate_200ul_pcr_full_skirt',
|
|
66
|
-
]
|
|
67
|
-
|
|
68
|
-
export const getLabwareDisplayName = (
|
|
69
|
-
labwareDef: LabwareDefinition2
|
|
70
|
-
): string => {
|
|
71
|
-
const { displayName } = labwareDef.metadata
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
getLabwareDefIsStandard(labwareDef) &&
|
|
75
|
-
RETIRED_LABWARE.includes(labwareDef.parameters.loadName)
|
|
76
|
-
) {
|
|
77
|
-
return `(Retired) ${displayName}`
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return displayName
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export const getTiprackVolume = (labwareDef: LabwareDefinition2): number => {
|
|
84
|
-
assert(
|
|
85
|
-
labwareDef.parameters.isTiprack,
|
|
86
|
-
`getTiprackVolume expected a tiprack labware ${getLabwareDefURI(
|
|
87
|
-
labwareDef
|
|
88
|
-
)}, but 'isTiprack' isn't true`
|
|
89
|
-
)
|
|
90
|
-
// NOTE: Ian 2019-04-16 assuming all tips are the same volume across the rack
|
|
91
|
-
const volume = labwareDef.wells.A1.totalLiquidVolume
|
|
92
|
-
assert(
|
|
93
|
-
volume >= 0,
|
|
94
|
-
`getTiprackVolume expected tip volume to be at least 0, got ${volume}`
|
|
95
|
-
)
|
|
96
|
-
return volume
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function getLabwareHasQuirk(
|
|
100
|
-
labwareDef: LabwareDefinition2,
|
|
101
|
-
quirk: string
|
|
102
|
-
): boolean {
|
|
103
|
-
const quirks = labwareDef.parameters.quirks
|
|
104
|
-
return quirks ? quirks.includes(quirk) : false
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export const intToAlphabetLetter = (
|
|
108
|
-
i: number,
|
|
109
|
-
lowerCase: boolean = false
|
|
110
|
-
): string => String.fromCharCode((lowerCase ? 96 : 65) + i)
|
|
111
|
-
// These utils are great candidates for unit tests
|
|
112
|
-
export const toWellName = ({
|
|
113
|
-
rowNum,
|
|
114
|
-
colNum,
|
|
115
|
-
}: {
|
|
116
|
-
rowNum: number
|
|
117
|
-
colNum: number
|
|
118
|
-
}): string => String.fromCharCode(rowNum + 65) + (colNum + 1)
|
|
119
|
-
|
|
120
|
-
function _parseWell(well: string): [string, number] {
|
|
121
|
-
const res = well.match(/([A-Z]+)(\d+)/)
|
|
122
|
-
const letters = res && res[1]
|
|
123
|
-
const number = res && parseInt(res[2])
|
|
124
|
-
|
|
125
|
-
if (!letters || number == null || Number.isNaN(number)) {
|
|
126
|
-
console.warn(
|
|
127
|
-
`Could not parse well ${well}. Got letters: "${
|
|
128
|
-
letters || 'void'
|
|
129
|
-
}", number: "${number || 'void'}"`
|
|
130
|
-
)
|
|
131
|
-
return ['', NaN]
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return [letters, number]
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/** A compareFunction for sorting an array of well names
|
|
138
|
-
* Goes down the columns (A1 to H1 on 96 plate)
|
|
139
|
-
* Then L to R across rows (1 to 12 on 96 plate)
|
|
140
|
-
*/
|
|
141
|
-
export function sortWells(a: string, b: string): number {
|
|
142
|
-
const [letterA, numberA] = _parseWell(a)
|
|
143
|
-
|
|
144
|
-
const [letterB, numberB] = _parseWell(b)
|
|
145
|
-
|
|
146
|
-
if (numberA !== numberB) {
|
|
147
|
-
return numberA > numberB ? 1 : -1
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (letterA.length !== letterB.length) {
|
|
151
|
-
// Eg 'B' vs 'AA'
|
|
152
|
-
return letterA.length > letterB.length ? 1 : -1
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return letterA > letterB ? 1 : -1
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export function splitWellsOnColumn(sortedArray: string[]): string[][] {
|
|
159
|
-
return sortedArray.reduce<string[][]>((acc, curr) => {
|
|
160
|
-
const lastColumn = acc.slice(-1)
|
|
161
|
-
|
|
162
|
-
if (lastColumn === undefined || lastColumn.length === 0) {
|
|
163
|
-
return [[curr]]
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const lastEle = lastColumn[0].slice(-1)[0].slice(1)
|
|
167
|
-
|
|
168
|
-
if (Number(curr.slice(1)) > Number(lastEle)) {
|
|
169
|
-
return [...acc, [curr]]
|
|
170
|
-
} else {
|
|
171
|
-
return [...acc.slice(0, -1), [...lastColumn[0], curr]]
|
|
172
|
-
}
|
|
173
|
-
}, [])
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
export const getWellDepth = (
|
|
177
|
-
labwareDef: LabwareDefinition2,
|
|
178
|
-
well: string
|
|
179
|
-
): number => labwareDef.wells[well].depth
|
|
180
|
-
|
|
181
|
-
// NOTE: this is used in PD for converting "offset from top" to "mm from bottom".
|
|
182
|
-
// Assumes all wells have same offset because multi-offset not yet supported.
|
|
183
|
-
// TODO: Ian 2019-07-13 return {[string: well]: offset} to support multi-offset
|
|
184
|
-
export const getWellsDepth = (
|
|
185
|
-
labwareDef: LabwareDefinition2,
|
|
186
|
-
wells: string[]
|
|
187
|
-
): number => {
|
|
188
|
-
const offsets = wells.map(well => getWellDepth(labwareDef, well))
|
|
189
|
-
|
|
190
|
-
if (uniq(offsets).length !== 1) {
|
|
191
|
-
console.warn(
|
|
192
|
-
`expected wells ${JSON.stringify(
|
|
193
|
-
wells
|
|
194
|
-
)} to all have same offset, but they were different. Labware def is ${getLabwareDefURI(
|
|
195
|
-
labwareDef
|
|
196
|
-
)}`
|
|
197
|
-
)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return offsets[0]
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export const getSlotHasMatingSurfaceUnitVector = (
|
|
204
|
-
deckDef: DeckDefinition,
|
|
205
|
-
addressableAreaName: string
|
|
206
|
-
): boolean => {
|
|
207
|
-
const matingSurfaceUnitVector = deckDef.locations.addressableAreas.find(
|
|
208
|
-
aa => aa.id === addressableAreaName
|
|
209
|
-
)?.matingSurfaceUnitVector
|
|
210
|
-
|
|
211
|
-
return Boolean(matingSurfaceUnitVector)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
export const getAreSlotsHorizontallyAdjacent = (
|
|
215
|
-
slotNameA?: string | null,
|
|
216
|
-
slotNameB?: string | null
|
|
217
|
-
): boolean => {
|
|
218
|
-
if (slotNameA == null || slotNameB == null) {
|
|
219
|
-
return false
|
|
220
|
-
}
|
|
221
|
-
const slotANumber = parseInt(slotNameA)
|
|
222
|
-
const slotBNumber = parseInt(slotNameB)
|
|
223
|
-
if (isNaN(slotBNumber) || isNaN(slotANumber)) {
|
|
224
|
-
return false
|
|
225
|
-
}
|
|
226
|
-
const orderedSlots = standardOt2DeckDef.locations.cutouts
|
|
227
|
-
// intentionally not substracting by 1 because trash (slot 12) should not count
|
|
228
|
-
const numSlots = orderedSlots.length
|
|
229
|
-
if (slotBNumber > numSlots || slotANumber > numSlots) {
|
|
230
|
-
return false
|
|
231
|
-
}
|
|
232
|
-
const slotWidth = orderedSlots[1].position[0] - orderedSlots[0].position[0]
|
|
233
|
-
const slotAPosition = orderedSlots[slotANumber - 1].position
|
|
234
|
-
const slotBPosition = orderedSlots[slotBNumber - 1].position
|
|
235
|
-
|
|
236
|
-
const yPositionSlotA = slotAPosition[1]
|
|
237
|
-
const yPositionSlotB = slotBPosition[1]
|
|
238
|
-
|
|
239
|
-
const xPositionSlotA = slotAPosition[0]
|
|
240
|
-
const xPositionSlotB = slotBPosition[0]
|
|
241
|
-
|
|
242
|
-
const areSlotsHorizontallyAdjacent =
|
|
243
|
-
yPositionSlotA === yPositionSlotB &&
|
|
244
|
-
Math.abs(xPositionSlotA - xPositionSlotB) === slotWidth
|
|
245
|
-
|
|
246
|
-
return areSlotsHorizontallyAdjacent
|
|
247
|
-
}
|
|
248
|
-
export const getAreSlotsVerticallyAdjacent = (
|
|
249
|
-
slotNameA?: string | null,
|
|
250
|
-
slotNameB?: string | null
|
|
251
|
-
): boolean => {
|
|
252
|
-
if (slotNameA == null || slotNameB == null) {
|
|
253
|
-
return false
|
|
254
|
-
}
|
|
255
|
-
const slotANumber = parseInt(slotNameA)
|
|
256
|
-
const slotBNumber = parseInt(slotNameB)
|
|
257
|
-
|
|
258
|
-
if (isNaN(slotBNumber) || isNaN(slotANumber)) {
|
|
259
|
-
return false
|
|
260
|
-
}
|
|
261
|
-
const orderedSlots = standardOt2DeckDef.locations.cutouts
|
|
262
|
-
// intentionally not substracting by 1 because trash (slot 12) should not count
|
|
263
|
-
const numSlots = orderedSlots.length
|
|
264
|
-
|
|
265
|
-
if (slotBNumber > numSlots || slotANumber > numSlots) {
|
|
266
|
-
return false
|
|
267
|
-
}
|
|
268
|
-
// take the y coord of slot 4, and subtact from y coord of slot 1
|
|
269
|
-
const slotHeight = orderedSlots[3].position[1] - orderedSlots[0].position[1]
|
|
270
|
-
const slotAPosition = orderedSlots[slotANumber - 1].position
|
|
271
|
-
const slotBPosition = orderedSlots[slotBNumber - 1].position
|
|
272
|
-
|
|
273
|
-
const yPositionSlotA = slotAPosition[1]
|
|
274
|
-
const yPositionSlotB = slotBPosition[1]
|
|
275
|
-
|
|
276
|
-
const xPositionSlotA = slotAPosition[0]
|
|
277
|
-
const xPositionSlotB = slotBPosition[0]
|
|
278
|
-
|
|
279
|
-
const areSlotsVerticallyAdjacent =
|
|
280
|
-
xPositionSlotA === xPositionSlotB &&
|
|
281
|
-
Math.abs(yPositionSlotA - yPositionSlotB) === slotHeight
|
|
282
|
-
|
|
283
|
-
return areSlotsVerticallyAdjacent
|
|
284
|
-
}
|
|
285
|
-
// TODO(jr, 11/12/23): rename this utility to mention that it
|
|
286
|
-
// is only used in the OT-2, same with getAreSlotsHorizontallyAdjacent
|
|
287
|
-
// and getAreSlotsVerticallyAdjacent
|
|
288
|
-
export const getAreSlotsAdjacent = (
|
|
289
|
-
slotNameA?: string | null,
|
|
290
|
-
slotNameB?: string | null
|
|
291
|
-
): boolean =>
|
|
292
|
-
getAreSlotsHorizontallyAdjacent(slotNameA, slotNameB) ||
|
|
293
|
-
getAreSlotsVerticallyAdjacent(slotNameA, slotNameB)
|
|
294
|
-
|
|
295
|
-
export const getIsLabwareAboveHeight = (
|
|
296
|
-
labwareDef: LabwareDefinition2,
|
|
297
|
-
height: number
|
|
298
|
-
): boolean => labwareDef.dimensions.zDimension > height
|
|
299
|
-
|
|
300
|
-
export const getAdapterName = (labwareLoadname: string): ThermalAdapterName => {
|
|
301
|
-
let adapterName: ThermalAdapterName = 'Universal Flat Adapter'
|
|
302
|
-
|
|
303
|
-
if (
|
|
304
|
-
labwareLoadname ===
|
|
305
|
-
'opentrons_96_pcr_adapter_nest_wellplate_100ul_pcr_full_skirt'
|
|
306
|
-
) {
|
|
307
|
-
adapterName = 'PCR Adapter'
|
|
308
|
-
} else if (
|
|
309
|
-
labwareLoadname === 'opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep'
|
|
310
|
-
) {
|
|
311
|
-
adapterName = 'Deep Well Adapter'
|
|
312
|
-
} else if (
|
|
313
|
-
labwareLoadname ===
|
|
314
|
-
'opentrons_96_flat_bottom_adapter_nest_wellplate_200ul_flat'
|
|
315
|
-
) {
|
|
316
|
-
adapterName = '96 Flat Bottom Adapter'
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
return adapterName
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
export const getCalibrationAdapterLoadName = (
|
|
323
|
-
moduleModel: ModuleModel
|
|
324
|
-
): string | null => {
|
|
325
|
-
switch (moduleModel) {
|
|
326
|
-
case 'heaterShakerModuleV1':
|
|
327
|
-
return 'opentrons_calibration_adapter_heatershaker_module'
|
|
328
|
-
case 'temperatureModuleV2':
|
|
329
|
-
return 'opentrons_calibration_adapter_temperature_module'
|
|
330
|
-
case 'thermocyclerModuleV2':
|
|
331
|
-
return 'opentrons_calibration_adapter_thermocycler_module'
|
|
332
|
-
default:
|
|
333
|
-
console.error(
|
|
334
|
-
`${moduleModel} does not have an associated calibration adapter`
|
|
335
|
-
)
|
|
336
|
-
return null
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
export const getDeckDefFromRobotType = (
|
|
341
|
-
robotType: RobotType
|
|
342
|
-
): DeckDefinition => {
|
|
343
|
-
// @ts-expect-error imported JSON not playing nice with TS. see https://github.com/microsoft/TypeScript/issues/32063
|
|
344
|
-
return robotType === 'OT-3 Standard'
|
|
345
|
-
? standardFlexDeckDef
|
|
346
|
-
: standardOt2DeckDef
|
|
347
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import isEqual from 'lodash/isEqual'
|
|
2
|
-
import uniqWith from 'lodash/uniqWith'
|
|
3
|
-
import round from 'lodash/round'
|
|
4
|
-
import sortedUniq from 'lodash/sortedUniq'
|
|
5
|
-
import uniq from 'lodash/uniq'
|
|
6
|
-
import type {
|
|
7
|
-
LabwareWell,
|
|
8
|
-
LabwareWellShapeProperties,
|
|
9
|
-
LabwareDefinition2,
|
|
10
|
-
LabwareWellGroupMetadata,
|
|
11
|
-
LabwareBrand,
|
|
12
|
-
} from '../types'
|
|
13
|
-
|
|
14
|
-
export interface LabwareWellGroupProperties {
|
|
15
|
-
xOffsetFromLeft: number
|
|
16
|
-
yOffsetFromTop: number
|
|
17
|
-
xSpacing: number | null
|
|
18
|
-
ySpacing: number | null
|
|
19
|
-
wellCount: number
|
|
20
|
-
shape: LabwareWellShapeProperties | null
|
|
21
|
-
depth: number | null
|
|
22
|
-
totalLiquidVolume: number | null
|
|
23
|
-
metadata: LabwareWellGroupMetadata
|
|
24
|
-
brand: LabwareBrand | null
|
|
25
|
-
}
|
|
26
|
-
const ROUNDING_PRECISION = 2
|
|
27
|
-
|
|
28
|
-
export function getUniqueWellProperties(
|
|
29
|
-
definition: LabwareDefinition2
|
|
30
|
-
): LabwareWellGroupProperties[] {
|
|
31
|
-
const { groups, wells, dimensions } = definition
|
|
32
|
-
|
|
33
|
-
return groups.map(group => {
|
|
34
|
-
const wellProps = group.wells.map(n => wells[n])
|
|
35
|
-
|
|
36
|
-
const wellDepths = wellProps.map<number>(w => w.depth)
|
|
37
|
-
const wellVolumes = wellProps.map<number>(w => w.totalLiquidVolume)
|
|
38
|
-
const wellShapes = wellProps.map<LabwareWellShapeProperties>(
|
|
39
|
-
(well: LabwareWell) =>
|
|
40
|
-
well.shape === 'circular'
|
|
41
|
-
? { shape: well.shape, diameter: well.diameter }
|
|
42
|
-
: {
|
|
43
|
-
shape: well.shape,
|
|
44
|
-
xDimension: well.xDimension,
|
|
45
|
-
yDimension: well.yDimension,
|
|
46
|
-
}
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
const xStart = wellProps[0]?.x ?? 0
|
|
50
|
-
const yStart = wellProps[0]?.y ?? 0
|
|
51
|
-
|
|
52
|
-
return {
|
|
53
|
-
metadata: group.metadata,
|
|
54
|
-
brand: group.brand || null,
|
|
55
|
-
xSpacing: getSpacingIfUniform(wellProps, 'x'),
|
|
56
|
-
ySpacing: getSpacingIfUniform(wellProps, 'y'),
|
|
57
|
-
xOffsetFromLeft: xStart,
|
|
58
|
-
yOffsetFromTop: round(dimensions.yDimension - yStart, ROUNDING_PRECISION),
|
|
59
|
-
wellCount: wellProps.length,
|
|
60
|
-
depth: getIfConsistent(wellDepths),
|
|
61
|
-
totalLiquidVolume: getIfConsistent(wellVolumes),
|
|
62
|
-
shape: getIfConsistent(wellShapes),
|
|
63
|
-
}
|
|
64
|
-
})
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function getIfConsistent<T>(items: T[]): T | null {
|
|
68
|
-
return uniqWith(items, isEqual).length === 1 ? items[0] : null
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// returning null means "spacing is irregular"; returning 0 means "there is only 1 well along the given axis"
|
|
72
|
-
export function getSpacingIfUniform(
|
|
73
|
-
wells: LabwareWell[],
|
|
74
|
-
axis: 'x' | 'y'
|
|
75
|
-
): number | null {
|
|
76
|
-
const wellPositions = sortedUniq(uniq(wells.map(well => well[axis])))
|
|
77
|
-
if (wellPositions.length < 2) return 0
|
|
78
|
-
|
|
79
|
-
const initialSpacing = round(
|
|
80
|
-
wellPositions[1] - wellPositions[0],
|
|
81
|
-
ROUNDING_PRECISION
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
for (let i = 2; i < wellPositions.length; i++) {
|
|
85
|
-
const pos = wellPositions[i]
|
|
86
|
-
const prevWellPos = wellPositions[i - 1]
|
|
87
|
-
const spacing = round(pos - prevWellPos, ROUNDING_PRECISION)
|
|
88
|
-
if (spacing !== initialSpacing) return null
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return Math.abs(initialSpacing)
|
|
92
|
-
}
|
package/js/helpers/orderWells.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import zipWith from 'lodash/zipWith'
|
|
2
|
-
import uniq from 'lodash/uniq'
|
|
3
|
-
import compact from 'lodash/compact'
|
|
4
|
-
import flatten from 'lodash/flatten'
|
|
5
|
-
|
|
6
|
-
export type WellOrderOption = 'l2r' | 'r2l' | 't2b' | 'b2t'
|
|
7
|
-
|
|
8
|
-
// labware definitions in shared-data have an ordering
|
|
9
|
-
// attribute which is an Array of Arrays of wells. Each inner
|
|
10
|
-
// Array represents a physical column of wells on the labware
|
|
11
|
-
// this function takes that 2d Array of columns and returns
|
|
12
|
-
// the same wells in a 2d Array where each inner Array represents
|
|
13
|
-
// a physical row of wells on the labware.
|
|
14
|
-
// e.g.
|
|
15
|
-
// [ \ [
|
|
16
|
-
// ['A1', 'B1'], === \ ['A1', 'A2']
|
|
17
|
-
// ['A2', 'B2'] === / ['B1', 'B2']
|
|
18
|
-
// ] / ]
|
|
19
|
-
//
|
|
20
|
-
const _orderingColsToRows = (ordering: string[][]): string[][] =>
|
|
21
|
-
zipWith(...ordering, (...col) => compact(uniq(col)))
|
|
22
|
-
|
|
23
|
-
// given a default "ordering" 2d array from labware definitions
|
|
24
|
-
// where each inner array represents a physical column of wells
|
|
25
|
-
// and well order option selections (e.g. 'l2r', 'r2l', 't2b', 'b2t')
|
|
26
|
-
// this function returns a 1d array of wells from the labware
|
|
27
|
-
// ordered by the given traversal technique
|
|
28
|
-
export const orderWells = (
|
|
29
|
-
defaultOrdering: string[][],
|
|
30
|
-
first: WellOrderOption,
|
|
31
|
-
second: WellOrderOption
|
|
32
|
-
): string[] => {
|
|
33
|
-
let orderedWells: string[][] = []
|
|
34
|
-
|
|
35
|
-
if (first === 't2b') {
|
|
36
|
-
if (second === 'l2r') {
|
|
37
|
-
orderedWells = defaultOrdering
|
|
38
|
-
} else if (second === 'r2l') {
|
|
39
|
-
orderedWells = defaultOrdering.slice().reverse()
|
|
40
|
-
}
|
|
41
|
-
} else if (first === 'b2t') {
|
|
42
|
-
if (second === 'l2r') {
|
|
43
|
-
orderedWells = defaultOrdering.map(col => col.slice().reverse())
|
|
44
|
-
} else if (second === 'r2l') {
|
|
45
|
-
orderedWells = defaultOrdering
|
|
46
|
-
.slice()
|
|
47
|
-
.reverse()
|
|
48
|
-
.map(col => col.slice().reverse())
|
|
49
|
-
}
|
|
50
|
-
} else if (first === 'l2r') {
|
|
51
|
-
if (second === 't2b') {
|
|
52
|
-
orderedWells = _orderingColsToRows(defaultOrdering)
|
|
53
|
-
} else if (second === 'b2t') {
|
|
54
|
-
orderedWells = _orderingColsToRows(defaultOrdering).slice().reverse()
|
|
55
|
-
}
|
|
56
|
-
} else if (first === 'r2l') {
|
|
57
|
-
if (second === 't2b') {
|
|
58
|
-
orderedWells = _orderingColsToRows(defaultOrdering).map(col =>
|
|
59
|
-
col.slice().reverse()
|
|
60
|
-
)
|
|
61
|
-
} else if (second === 'b2t') {
|
|
62
|
-
orderedWells = _orderingColsToRows(defaultOrdering)
|
|
63
|
-
.slice()
|
|
64
|
-
.reverse()
|
|
65
|
-
.map(col => col.slice().reverse())
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return flatten(orderedWells)
|
|
69
|
-
}
|