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 @@ -6,7 +6,7 @@ import {
THERMOCYCLER_MODULE_TYPE,
} from '@opentrons/shared-data'
import {
constructInvariantContextFromRunCommands,
constructInvariantContextFromAnalysis,
getResultingTimelineFrameFromRunCommands,
} from '@opentrons/step-generation'

Expand Down Expand Up @@ -89,11 +89,11 @@ export function VisualizerContainer(
)

const currentCommandsSlice = commands.slice(0, selectedCommandIndex + 1)
const invariantContextFromRunCommands =
constructInvariantContextFromRunCommands(commands)
const invariantContextFromAnalysis =
constructInvariantContextFromAnalysis(analysis)
const { frame, invariantContext } = getResultingTimelineFrameFromRunCommands(
currentCommandsSlice,
invariantContextFromRunCommands
invariantContextFromAnalysis
)

const handlePlayPause = (): void => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ const mockAnalysis = {
'protocol-designer@chore_release-pd-8.6.0-20251016-222252',
source: 'Protocol Designer',
},
modules: [],
labware: [],
pipettes: [],
result: 'ok',
robotType: 'OT-3 Standard',
runTimeParameters: [],
Expand Down
201 changes: 201 additions & 0 deletions step-generation/src/utils/constructInvariantContextFromAnalysis.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import {
getLabwareDefinitionsByURIForProtocol,
getModuleType,
getPipetteSpecsV2,
} from '@opentrons/shared-data'

import { uuid } from '.'
import { GRIPPER_LOCATION } from '../constants'
import { createStagingAreaForInvariantContext } from './misc'

import type {
PickUpTipRunTimeCommand,
ProtocolAnalysisOutput,
RunTimeCommand,
} from '@opentrons/shared-data'
import type {
InvariantContext,
LabwareEntities,
ModuleEntities,
PipetteEntities,
StagingAreaEntities,
TrashBinEntities,
WasteChuteEntities,
} from '../types'

export function constructInvariantContextFromAnalysis(
analysis: ProtocolAnalysisOutput
): InvariantContext {
const { labware, modules, pipettes, commands } = analysis
const labwareDefinitions = getLabwareDefinitionsByURIForProtocol(commands)

const moduleEntities = modules.reduce<ModuleEntities>((acc, module) => {
const { id, model } = module

return {
...acc,
[id]: {
id,
type: getModuleType(model),
model,
pythonName: 'n/a',
},
}
}, {})

const labwareEntities = labware.reduce<LabwareEntities>(
(acc, loadedLabware) => {
const { id, definitionUri } = loadedLabware
const def = labwareDefinitions[definitionUri]
if (def.schemaVersion === 3) {
return acc
}
return {
...acc,
[id]: {
id,
labwareDefURI: definitionUri,
def,
pythonName: 'n/a',
},
}
},
{}
)

const pipetteEntities = pipettes.reduce<PipetteEntities>((acc, pipette) => {
const { id, pipetteName } = pipette
const spec = getPipetteSpecsV2(pipetteName)
const tiprackIdsAssosciatedWithPipette = commands.filter(
(command): command is PickUpTipRunTimeCommand =>
command.commandType === 'pickUpTip' && command.params.pipetteId === id
)
const matchingLabwareEntities = tiprackIdsAssosciatedWithPipette.map(
pickUpTipCommand => labwareEntities[pickUpTipCommand.params.labwareId]
)
const tiprackDefURIs = Array.from(
new Set(matchingLabwareEntities.map(entity => entity.labwareDefURI))
)
const tiprackLabwareDefs = Array.from(
new Set(matchingLabwareEntities.map(entity => entity.def))
)
if (spec == null) {
return acc
}

acc[id] = {
name: pipetteName,
id,
tiprackLabwareDef: tiprackLabwareDefs,
tiprackDefURI: tiprackDefURIs,
spec,
pythonName: 'n/a',
}

return acc
}, {})
const otherEntities = commands.reduce(
(
acc: Omit<
InvariantContext,
'labwareEntities' | 'moduleEntities' | 'pipetteEntities'
>,
command: RunTimeCommand
) => {
Comment on lines +97 to +104
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const otherEntities = commands.reduce(
(
acc: Omit<
InvariantContext,
'labwareEntities' | 'moduleEntities' | 'pipetteEntities'
>,
command: RunTimeCommand
) => {
const otherEntities = commands.reduce<
Omit<
InvariantContext,
'labwareEntities' | 'moduleEntities' | 'pipetteEntities'
>
>(
(acc, command: RunTimeCommand) => {

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the opposite of the other suggestions lol. i'm gonna leave as is

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm what do you mean? Typing the return of the reduce rather than the acc is consistent above, no?

Fine with me to leave as is though

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ooooo i definitely didn't read clearly. my bad. ya i'll address this! thanks!

if (command.commandType === 'loadLidStack' && command.result != null) {
const { params } = command
const newStagingAreaEntities: StagingAreaEntities =
createStagingAreaForInvariantContext(params)

return {
...acc,
stagingAreaEntities: {
...acc.stagingAreaEntities,
...newStagingAreaEntities,
},
}
} else if (
(command.commandType === 'loadLabware' ||
command.commandType === 'loadLid') &&
command.result != null
) {
const { params } = command

const newStagingAreaEntities: StagingAreaEntities =
createStagingAreaForInvariantContext(params)

return {
...acc,
stagingAreaEntities: {
...acc.stagingAreaEntities,
...newStagingAreaEntities,
},
}
} else if (
command.commandType === 'moveToAddressableArea' ||
command.commandType === 'moveToAddressableAreaForDropTip'
) {
const addressableAreaName = command.params.addressableAreaName
const id = `${uuid()}:${addressableAreaName}`
let location: string = GRIPPER_LOCATION
if (addressableAreaName === 'fixedTrash') {
location = 'cutout12'
} else if (addressableAreaName.includes('WasteChute')) {
location = 'cutoutD3'
} else if (addressableAreaName.includes('movableTrash')) {
location = `cutout${addressableAreaName.split('movableTrash')[1]}`
}
let trashBinEntities: TrashBinEntities = acc.trashBinEntities
if (
!Object.values(acc.trashBinEntities).some(
entity => entity.location === location
) &&
addressableAreaName.includes('movableTrash')
) {
trashBinEntities = {
...acc.trashBinEntities,
[id]: {
pythonName: 'trash_bin_1',
id,
location,
},
}
}
let wasteChuteEntities: WasteChuteEntities = acc.wasteChuteEntities
if (addressableAreaName.includes('WasteChute')) {
wasteChuteEntities = {
[id]: {
pythonName: 'waste_chute',
id,
location,
},
}
}
Comment on lines +165 to +173
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't we have the same if statement above?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nah the other one is for trash bin

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking at L143

return {
...acc,
trashBinEntities,
wasteChuteEntities,
}
}

return acc
},
{
wasteChuteEntities: {},
trashBinEntities: {},
stagingAreaEntities: {},
// the timeline scrubber doesn't visualize gripper right now
gripperEntities: {},
// this util is used for the timeline scrubber. It grabs liquid info from analysis
// so this will not be wired up right now
liquidEntities: {},
config: { OT_PD_DISABLE_MODULE_RESTRICTIONS: true },
}
)
return {
labwareEntities,
pipetteEntities,
moduleEntities,
...otherEntities,
}
}
Loading
Loading