How does PyLabRobot handle liquid classes?

Hi, I am very familiar with Venus and their liquid class editor. I was wondering a few things:

  1. Generally how do you specify the liquid class parameters for a given aspiration?
  2. Is there a similar tool to Hamilton Liquid Class editor?

Thanks

1 Like

They actually are quite different.

In VENUS, as you know, a liquid class specifies many parameters, like aspiration flow rate, volume correction, etc. The user has to specify the liquid class using a string.

In PyLabRobot, a liquid class is basically an enumeration of the different types of liquid that one would use (water, DNA, glycerol, etc.) See pylabrobot/abstract.py at main · PyLabRobot/pylabrobot · GitHub. The default is water. Each robot (LiquidHandlerBackend) can use this information about the type of liquid to determine the best aspiration/dispense parameters. Note that this is intended to fill in parameters with value Default, and that user specified parameters should always take precedence. This ‘filling in of defaults’ is done on a parameter-by-parameter basis, so if you specify a flow rate for example, the best volume correction curve will still be found automatically. If no flow rate were specified, that parameter would also have a ‘smart default’.

In the STAR backend specifically, which is the one used for Hamilton robots, the available information is combined to find the best VENUS liquid class. That is done by combining the PLR Liquid Class (say “water”), with other information (such as whether an operation is an aspiration or dispense, whether it’s a jet or surface dispense, etc.). Using this combination, the best VENUS Liquid Class is found (see pylabrobot/hamilton.py at main · PyLabRobot/pylabrobot · GitHub). Currently, no option exists to manually specify a liquid class in STAR, but I could add that if you want.

The venus liquid classes that exist in PyLabRobot can be edited by editing the Python file, but I would not necessarily recommend this. It would be much better if we could just have the user pass a liquid class using a parameter, in case they want to override the automatic selection. Let me know if you need that.

This is not the default behavior, or necessarily recommended, since it complicates robot agnosticism, and ‘plain’ parameters are much simpler and more expressive. So I would recommend setting the parameters in LiquidHandler:

Or, if need be, using backend_kwargs (parameters that are ignored by LiquidHandler and passed along to the backend, so basically the parameters you see here):

If anything here sounds imperfect, I’m happy to discuss alternatives!

Hope that helps!

1 Like

Interesting! Yes I think there would need to be some flexibility built into this abstraction as when working with these instruments nearly every customer will design and deploy a custom liquid class, even the standard water liquid class needs to be changed. All these liquid classes are effected by humidity and elevation (For Hamiltons), so a lot of the time the standards don’t work if you are not in the exact climate as Reno, where they were developed for Hamiltons.

This is where being agnostic with instruments may get tricky, as they fundamentally have different pipetting channels. Hamilton operates on a air displacement model I am not sure how Opentrons, tecans, etc operate

Along with that Hamilton’s use a “correction curve” to move the actual stepper different increments based on the liquid class’s correction curve:

This correction curve can change based on tips size, liquid, humidity, and elevation. These correction curves are 99% of the time not linear and need to be measured manually (see Hamilton’s Liquid Class Verification Kit LVK)

How should we go about introducing more flexibility? Specifying parameters on LH already overrides the parameters inferred from the liquid class.

Consider the following example:

lh.aspirate(my_plate["A1"], vols=[100], flow_rates=[100])

Let’s think about the following as an alternative/additional implementation:

lc = HamiltonLiquidClass(
  ...
  aspiration_flow_rate=100.0,
  ...
)
lh.aspirate(my_plate["A1"], vols=[100], liquid_classes=[lc])

I see two benefits:

  1. The correction curve that is currently implemented would be overridden. There is no way to do that right now, which is wrong.
  2. It become easier to group parameters that are often used together. For example, having two liquid classes defined and conditionally using one over the other would just be a single parameter change. And it’s easier to reuse the parameter groups later.

On the other hand, this makes the API more ambiguous (what’s the suggested way of specifying the flow rate? What should lh.aspirate(my_plate["A1"], vols=[100], flow_rates=[100], liquid_classes=[lc]) do?). How would we serialize this? Should LH know about liquid classes, and how is that different from just specifying them as plain parameters? Passing both liquid classes and parameters to the backend would introduce ambiguity in the Standard Form, and I’m very much opposed to that. Specifically regarding #2: what is the benefit over constants at the top of the file?

This leads me to conclude that something like

vol = 100
if HAMILTON:
  vol = correct_hamilton_volume(vol)
vol *= MY_MYSTERIOUS_CORRECTION_FACTOR # load from a config file
lh.aspirate(my_plate["A1"], vols=[vol], flow_rates=[100],
  do_not_correct_volume=True) # change param name obviously

is much better.

Just a stream of consciousness that I would love to discuss. Happy to have my mind changed.tr

These correction curves are 99% of the time not linear and need to be measured manually (see Hamilton’s Liquid Class Verification Kit LVK)

That seems super useful and there should definitely be a PyLabRobot integration. Do you have access to one?

Hamilton’s LVK looks like a gravimetric scale with some appreciable precision. Can we build our own gravimetric or colorimetric calibration tools that are hardware-agnostic? (use your own usb scale or plate reader)

If you have a device that connects, this must be possible (would obviously require a baseline too). (One plate reader is already integrated.) That would be an amazing PLR-based app!

1 Like

Think we can get this working. I’ll update you when we need to create new liquid classes in PLR (hopefully soon…)

1 Like