Conditionals
We are taking a plate from a stacker and randomly deciding with a dice roll and a coin file whether it goes to the bin, stays where is is or makes it through to a plate hotel.
from linq.task import (
ActionTask,
CodeTask,
ConditionalSourceTask,
If,
LabwareSource,
LuaFunction,
)
HEAD = 1
TAILS = 0
plate_type = labware.LabwareType(id="microplate_96")
plate = labware.Labware(
id="plate_1",
labware_type=plate_type,
starting_location=LabwareLocation(
instrument=stacker,
slot=1
),
batch=1,
)
workflow = Workflow(
workcell=conditional_workcell,
name="Conditional Workflow",
author="Automata",
description="Conditional Workflow",
version="0.1",
scheduler_version=get_latest_scheduler_version(),
labware_types=[plate_type],
labware=[plate],
)
Single conditional
workflow.If(roll_the_dice.out().equals_any([1, 6]), id="dice-roll-conditional").Then(
# Move to hotel
move_plate_dice_roll := ActionTask(
id="move-plate-to-hotel-on-dice-roll",
description="Dice is 1 or 6, the plate survives and moves to the hotel.",
time_estimate=30,
instrument_type=hotel.type,
labware_sources=[LabwareSource(labware=plate)],
),
).ElseIf(roll_the_dice.out() == 2).Then(
# Bin it
ActionTask(
id="bin-plate",
description="Dice is 2, the plate does not make it.",
time_estimate=30,
instrument_type=bin1.type,
labware_sources=[LabwareSource(labware=plate)],
),
).Else(
# Leave it where it is
leave_the_plate_on_stacker := ActionTask(
id="leave-plate-on-stacker",
description="Dice is not 1, 2 or 6, the plate stays where it is.",
time_estimate=30,
instrument_type=stacker.type,
action="do_nothing",
labware_sources=[LabwareSource(labware=plate)],
)
)
Nested conditional
workflow.If(roll_the_dice.out().equals_any([1, 6]), id="dice-roll-conditional").Then(
move_plate_dice_roll := ActionTask(
id="move-plate-to-hotel-on-dice-roll",
description="Dice is 1 or 6, the plate survives.",
time_estimate=30,
instrument_type=hotel.type,
labware_sources=[LabwareSource(labware=plate)],
),
).Else(
If(flip_the_coin.out() == HEADS, id="flip-coin-conditional")
.Then(
move_plate_coin_flip := ActionTask(
id="move-plate-to-hotel-on-coin-flip",
description="Dice is not 1 or 6 but Coin is heads, the plate survives.",
time_estimate=30,
instrument_type=hotel.type,
labware_sources=[LabwareSource(labware=plate)],
),
)
.Else(
ActionTask(
id="bin-plate",
description="Dice is not 1 or 6, Coin is tails, the plate does not make it.",
time_estimate=30,
instrument_type=bin1.type,
labware_sources=[LabwareSource(labware=plate)],
),
),
# NOTE: We need a do nothing task here to ensure that the labware source is defined for
# the final task store-in-hotel which exists outside the If block
do_nothing := ActionTask(
id="do-nothing-after-move_plate_coin_flip",
description="Do nothing task is required to give tasks outside the If block a labware source",
time_estimate=1,
instrument_type=hotel.type,
action="do_nothing",
labware_sources=[LabwareSource(labware=plate, source_task=move_plate_coin_flip)],
),
)
Using ConditionalSourceTask for Downstream Tasks
When multiple conditional branches produce labware that needs to be used by a downstream task, use ConditionalSourceTask to specify all possible labware sources. This is necessary because at planning time, the actual outcome of the conditional is not known, so you must provide all options that may evaluate to true.
# After the nested conditional above, we want a final task that uses the plate
# regardless of which branch was taken (hotel, bin, or stacker)
# ConditionalSourceTask allows us to have one final task that accepts labware from any branch
final_plate_processing = ActionTask(
id="final-plate-processing",
description="Final processing for plate, regardless of routing path",
time_estimate=60,
instrument_type=workstation.type,
labware_sources=[
LabwareSource(
labware=plate,
# Specify all possible source tasks from conditional branches
# The planner will account for all possibilities during planning
source_task=ConditionalSourceTask(
tasks=[
move_plate_dice_roll, # If branch: dice roll is 1 or 6
move_plate_coin_flip, # Nested Else->Then: coin flip is heads
leave_the_plate_on_stacker, # Nested Else->Else: all other cases
]
),
)
],
)
# Add the final task to the workflow
workflow.add_task(final_plate_processing)
Key Points about ConditionalSourceTask
Multiple conditional branches: When a downstream task could receive labware from multiple conditional branches, use
ConditionalSourceTaskto reference all possible source tasksPlanning constraint: The planner accounts for all possibilities and generates a plan that is valid regardless of which branch executes at runtime
Runtime execution: At execution time, only the actual labware from the branch that executed will be used as input to the downstream task
Workflow simplification: Eliminates the need for duplicate downstream tasks for each conditional branch or complex intermediate routing logic