Worklist Basics#

The most flexible way to give pipetting instructions to the Tecan EVO or Fluent are Gemini worklist files (*.gwl).

A simple worklist might look like this:

W1;
A;MasterMix;;;1;;50.00;;;;
D;AssayPlate;;;1;;50.00;;;;
W1;
A;MasterMix;;;2;;50.00;;;;
D;AssayPlate;;;2;;50.00;;;;

Between the ;, the EVOware or Fluent Control accept various parameters such as the liquid class or rack type. As you might guess from the above example you don’t want to write such worklist files by hand.

Instead, robotools can write these worklists for you!

This is typically done with a robot-specific subtype of BaseWorklist.

classDiagram BaseWorklist <|-- EvoWorklist BaseWorklist <|-- FluentWorklist class BaseWorklist{ filepath : Optional[Path] save() comment() wash() transfer()* } class EvoWorklist{ - transfer() - evo_aspirate() - evo_dispense() } class FluentWorklist{ - transfer() }

The BaseWorklist classes are context managers that automatically creates a worklist with the commands corresponding to the methods you are calling.

Let’s see an example 👇

import robotools

Labware Definition#

Let’s say we are writing a simple assay procedure where samples and mastermix are combined in an MTP.

# Let's say we have 6 1.5 mL Eppis with 500 µL sample each.
samples = robotools.Labware("Samples", 6, 1, min_volume=20, max_volume=1500, initial_volumes=500)

# We want to run an assay in a microtiterplate
assay = robotools.Labware("AssayMTP", 8, 12, min_volume=30, max_volume=300)

# We have a trough with assay mastermix
mastermix = robotools.Trough("MasterMix", 8, 1, min_volume=5000, max_volume=25_000, initial_volumes=10_000)

# To inspect the initial volumes:
print(samples)
print(assay)
print(mastermix)
Samples
[[500.]
 [500.]
 [500.]
 [500.]
 [500.]
 [500.]]
AssayMTP
[[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]
MasterMix
[[10000.]]

Choosing the Worklist Type#

As shown above, there are three worklist classes, with BaseWorklist being the generic one, and EvoWorklist/FluentWorklist featuring slightly different APIs.

Notable differences between EvoWorklist and FluentWorklist are:

  • EvoWorklist also has evo_wash(), evo_aspirate() and evo_dispense() methods.

  • Numbering of trough wells in the generated worklist commands accounts for EVO/Fluent differences.

Writing a Worklist#

The BaseWorklist has a ton of methods that are available with both EvoWorklist and FluentWorklist. It doesn’t make sense to list them all here, but you can use help(robotools.BaseWorklist) or look them up in the documentation.

The most commonly used method is .transfer():

help(robotools.EvoWorklist.transfer)
Help on function transfer in module robotools.evotools.worklist:

transfer(self, source: robotools.liquidhandling.labware.Labware, source_wells: Union[str, Sequence[str], numpy.ndarray], destination: robotools.liquidhandling.labware.Labware, destination_wells: Union[str, Sequence[str], numpy.ndarray], volumes: Union[float, Sequence[float], numpy.ndarray], *, label: Optional[str] = None, wash_scheme: int = 1, partition_by: str = 'auto', **kwargs) -> None
    Transfer operation between two labwares.
    
    Parameters
    ----------
    source : liquidhandling.Labware
        Source labware
    source_wells : str or iterable
        List of source well ids
    destination : liquidhandling.Labware
        Destination labware
    destination_wells : str or iterable
        List of destination well ids
    volumes : float or iterable
        Volume(s) to transfer
    label : str
        Label of the operation to log into labware history
    wash_scheme : int
        Wash scheme to apply after every tip use
    partition_by : str
        one of 'auto' (default), 'source' or 'destination'
            'auto': partitioning by source unless the source is a Trough
            'source': partitioning by source columns
            'destination': partitioning by destination columns
    kwargs
        Additional keyword arguments to pass to aspirate and dispense.
        Most prominent example: `liquid_class`.
        Take a look at `Worklist.aspirate_well` for the full list of options.

The worklist is created by entering its context manager.

We can optionally pass a file path and it will automatically write the worklist to that file when leaving the context.

n_samples = samples.n_rows
n_replicates = 3

with robotools.EvoWorklist("02_assay.gwl") as wl:
    wl.wash()
    # Add triplicates of the samples
    for r in range(n_replicates):
        wl.transfer(
            samples, samples.wells,
            assay, assay.wells[:n_samples, r],
            10,
            label=f"Add replicate {r+1} samples",
        )
    
    # Select trough wells to aspirate from
    trough_wells = robotools.get_trough_wells(
        n=n_samples*n_replicates,
        trough_wells=mastermix.wells[:,0],
    )
    
    # Add buffer to all wells
    wl.transfer(
        mastermix, trough_wells,
        assay, assay.wells[:n_samples,:n_replicates],
        50,
        label="Add mastermix",
    )

Our three labwares were modified by the pipetting steps. We can inspect the history of the 96-well plate to check if we selected the right wells & volumes:

print(assay.report)
AssayMTP
initial
[[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]

Add replicate 1 samples
[[10.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]]

Add replicate 2 samples
[[10. 10.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10. 10.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10. 10.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10. 10.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10. 10.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10. 10.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]]

Add replicate 3 samples
[[10. 10. 10.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10. 10. 10.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10. 10. 10.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10. 10. 10.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10. 10. 10.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [10. 10. 10.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]]

Add mastermix
[[60. 60. 60.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [60. 60. 60.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [60. 60. 60.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [60. 60. 60.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [60. 60. 60.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [60. 60. 60.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]]

If a filepath was passed, the worklist automatically writes worklist (wl) to it, overwriting any previous content.

with Worklist(filepath=...) as wl:
    ...

Note that it includes the labels as comments.

with open("02_assay.gwl") as wlfile:
    print(wlfile.read())
W1;
C;Add replicate 1 samples
A;Samples;;;1;;10.00;;;;
D;AssayMTP;;;1;;10.00;;;;
W1;
A;Samples;;;2;;10.00;;;;
D;AssayMTP;;;2;;10.00;;;;
W1;
A;Samples;;;3;;10.00;;;;
D;AssayMTP;;;3;;10.00;;;;
W1;
A;Samples;;;4;;10.00;;;;
D;AssayMTP;;;4;;10.00;;;;
W1;
A;Samples;;;5;;10.00;;;;
D;AssayMTP;;;5;;10.00;;;;
W1;
A;Samples;;;6;;10.00;;;;
D;AssayMTP;;;6;;10.00;;;;
W1;
C;Add replicate 2 samples
A;Samples;;;1;;10.00;;;;
D;AssayMTP;;;9;;10.00;;;;
W1;
A;Samples;;;2;;10.00;;;;
D;AssayMTP;;;10;;10.00;;;;
W1;
A;Samples;;;3;;10.00;;;;
D;AssayMTP;;;11;;10.00;;;;
W1;
A;Samples;;;4;;10.00;;;;
D;AssayMTP;;;12;;10.00;;;;
W1;
A;Samples;;;5;;10.00;;;;
D;AssayMTP;;;13;;10.00;;;;
W1;
A;Samples;;;6;;10.00;;;;
D;AssayMTP;;;14;;10.00;;;;
W1;
C;Add replicate 3 samples
A;Samples;;;1;;10.00;;;;
D;AssayMTP;;;17;;10.00;;;;
W1;
A;Samples;;;2;;10.00;;;;
D;AssayMTP;;;18;;10.00;;;;
W1;
A;Samples;;;3;;10.00;;;;
D;AssayMTP;;;19;;10.00;;;;
W1;
A;Samples;;;4;;10.00;;;;
D;AssayMTP;;;20;;10.00;;;;
W1;
A;Samples;;;5;;10.00;;;;
D;AssayMTP;;;21;;10.00;;;;
W1;
A;Samples;;;6;;10.00;;;;
D;AssayMTP;;;22;;10.00;;;;
W1;
C;Add mastermix
A;MasterMix;;;1;;50.00;;;;
D;AssayMTP;;;1;;50.00;;;;
W1;
A;MasterMix;;;2;;50.00;;;;
D;AssayMTP;;;2;;50.00;;;;
W1;
A;MasterMix;;;3;;50.00;;;;
D;AssayMTP;;;3;;50.00;;;;
W1;
A;MasterMix;;;4;;50.00;;;;
D;AssayMTP;;;4;;50.00;;;;
W1;
A;MasterMix;;;5;;50.00;;;;
D;AssayMTP;;;5;;50.00;;;;
W1;
A;MasterMix;;;6;;50.00;;;;
D;AssayMTP;;;6;;50.00;;;;
W1;
A;MasterMix;;;7;;50.00;;;;
D;AssayMTP;;;9;;50.00;;;;
W1;
A;MasterMix;;;8;;50.00;;;;
D;AssayMTP;;;10;;50.00;;;;
W1;
A;MasterMix;;;1;;50.00;;;;
D;AssayMTP;;;11;;50.00;;;;
W1;
A;MasterMix;;;2;;50.00;;;;
D;AssayMTP;;;12;;50.00;;;;
W1;
A;MasterMix;;;3;;50.00;;;;
D;AssayMTP;;;13;;50.00;;;;
W1;
A;MasterMix;;;4;;50.00;;;;
D;AssayMTP;;;14;;50.00;;;;
W1;
A;MasterMix;;;5;;50.00;;;;
D;AssayMTP;;;17;;50.00;;;;
W1;
A;MasterMix;;;6;;50.00;;;;
D;AssayMTP;;;18;;50.00;;;;
W1;
A;MasterMix;;;7;;50.00;;;;
D;AssayMTP;;;19;;50.00;;;;
W1;
A;MasterMix;;;8;;50.00;;;;
D;AssayMTP;;;20;;50.00;;;;
W1;
A;MasterMix;;;1;;50.00;;;;
D;AssayMTP;;;21;;50.00;;;;
W1;
A;MasterMix;;;2;;50.00;;;;
D;AssayMTP;;;22;;50.00;;;;
W1;
%load_ext watermark
%watermark -idu
Last updated: 2024-04-23T15:21:04.769387+02:00