pylabrobot icon indicating copy to clipboard operation
pylabrobot copied to clipboard

Well compute_height_from_volume method integration (LLF part 2)

Open BioCam opened this issue 1 year ago • 0 comments

Hi everyone,

This PR is part 2 in a series to expose liquid level following (LLF) in PLR. See #136 for part 1.

In this PR I

  • added a new class argument to Well in resources/well.py called compute_height_from_volume,
  • added a new class attribute to Well called _compute_height_from_volume which is assigned to the value from compute_height_from_volume,
  • added a new class method to Well called compute_volume_from_height which executes the function stored in _compute_height_from_volume if it is not None.

This implementation is a direct counter to _compute_volume_from_height which already exists.

Example definition

I showcase how to define this method in resources/thermo_fisher/plates.py:


# # # # # # # # # # ThermoScientific_96_1200ul_Rd # # # # # # # # # #

def _compute_volume_from_height_ThermoScientific_96_1200ul_Rd(h: float):
  if h > 20.5:
    raise ValueError(f"Height {h} is too large for ThermoScientific_96_1200ul_Rd")
  return calculate_liquid_volume_container_2segments_square_ubottom(
    x=8.15,
    h_cuboid=16.45,
    liquid_height=h)

def _compute_height_from_volume_ThermoScientific_96_1200ul_Rd(liquid_volume: float):
  if liquid_volume > 1260: # 5% tolerance
    raise ValueError(f"Volume {liquid_volume} is too large for ThermoScientific_96_1200ul_Rd")
  return round(calculate_liquid_height_in_container_2segments_square_ubottom(
    x=8.15,
    h_cuboid=16.45,
    liquid_volume=liquid_volume),3)

def ThermoScientific_96_1200ul_Rd(name: str, with_lid: bool = False) -> Plate:
  """ Fisher Scientific/Thermo Fisher cat. no.: 10243223/AB1127.
  - Material: Polypropylene (AB-1068, polystyrene)
  - Suitable for Autoclaving (15 minutes at 121°C) or Gamma Irradiation
  - Resistant to DMSO (100%); Ethanol (100%); Isopropanol (100%)
  - Round well shape designed for optimal sample recovery or square shape to
    maximize sample volume within ANSI footprint design
  - Each well has an independent sealing rim to prevent cross-contamination
  - U-bottomed wells ideally suited for sample resuspension
  - Sealing options: Adhesive Seals, Heat Seals, Storage Plate Caps and Cap
    Strips, and Storage Plate Sealing Mats
  - Cleanroom manufactured
  - ANSI-format for compatibility with automated systems
  """
  return Plate(
    name=name,
    size_x=127.0,
    size_y=86.0,
    size_z=24.0,
    with_lid=with_lid,
    model="ThermoScientific_96_1200ul_Rd",
    lid_height=5,
    items=create_equally_spaced(Well,
      num_items_x=12,
      num_items_y=8,
      dx=9.6,
      dy=7.3,
      dz=0.2,
      item_dx=9,
      item_dy=9,
      size_x=8.3,
      size_y=8.3,
      size_z=20.5,
      bottom_type=WellBottomType.U,
      cross_section_type=CrossSectionType.RECTANGLE,
      compute_volume_from_height=_compute_volume_from_height_ThermoScientific_96_1200ul_Rd,
      compute_height_from_volume=_compute_height_from_volume_ThermoScientific_96_1200ul_Rd
    ),
  )

Example use

This now enables on-the-fly calculations of the height of a liquid inside a container/well.

# Define labware & position
plt_carrier_1[0] = ThermoScientific_96_1200ul_Rd = ThermoScientific_96_1200ul_Rd(name="ThermoScientific_96_1200ul_Rd")

# Test calculations
for x in np.arange(0,26.8,0.4):
    vol_cal = ThermoScientific_96_1200ul_Rd['A1'][0].compute_volume_from_height(x)
    height_calc = ThermoScientific_96_1200ul_Rd['A1'][0].compute_height_from_volume(vol_cal)
    print(f"start_height_for_test={round(x,2)}")
    print(f"vol_cal={round(vol_cal,2)}")
    print(f"height_calc={round(height_calc,2)}\n")

Together with the volume tracking this enables a good estimate of at what height (relative to the bottom of the well) the meniscus of each liquid is, and can be used to calculate where the meniscus will be after a given aspiration/dispensation.

-> With this information everyone can then execute their own LLF using the aspirate argument surface_following_distance (thank you, @rickwierenga, for pointing me to this).

(At the moment, PLR does not offer complex commands directly from the library but everyone is expected to generate these themselves. This is i.a. to avoid unpredicted machine behaviour.)

Next steps

At the moment, compute_height_from_volume() will raise a NotImplementedError for any plate besides the showcase ThermoScientific_96_1200ul_Rd.

To enable this feature for other plates we have to define and add the corresponding function to each plate definition, probably in quite a couple of separate PRs :)

BioCam avatar May 24 '24 17:05 BioCam