PyLabRobot / pylabrobot

An interactive & hardware agnostic interface for lab automation
https://docs.pylabrobot.org
MIT License
153 stars 54 forks source link

container geometry: support cone frustum #193

Open rickwierenga opened 1 month ago

rickwierenga commented 1 month ago

many wells actually turn out to be frustums of cylinders, not cylinders directly.

image image

https://www.celltreat.com/wp-content/uploads/6-Well-Plate.pdf https://www.corning.com/catalog/cls/documents/drawings/MicroplateDimensions96-384-1536.pdf

rickwierenga commented 1 month ago

I was thinking this would be kinda neat:

well = Well(
  ...,
  sections=[
    Cylinder(
      height=10,
      diameter=20,
    ),
    CylinderFrustum(
      height=10,
      top_diameter=20,
      bottom_diameter=10,
    ),
  ]
)

and we could generate compute_volume_from_height and compute_height_from_volume quite easily from the sections' own definitions.

But, as @BioCam showed in https://github.com/PyLabRobot/pylabrobot/pull/168, sometimes people might want to define their own compute_volume_from_height and compute_height_from_volume. While this is doable with the above api as so:

class CustomSection(Section):
  def __init__(...):
    ...

  def compute_volume_from_height(self, height):
    return some_formula(height)

  def compute_height_from_volume(self, volume):
    return some_other_formula(volume)

this is not as nice. And all you really care about in the end is compute_volume_from_height and compute_height_from_volume.

I think the best we can do is provide nice volume_functions, as @BioCam wrote, but maybe further decompose these:

so that we can easily allow users to write more complex geometries by just functions:

def calculate_liquid_volume_container_2segments_square_vbottom(
  x: float,
  y: float,
  h_pyramid: float,
  h_cube: float,
  liquid_height: float
) -> float:
  if liquid_height <= h_pyramid:
    return compute_pyramid_volume(base_area=x*y, h_pyramid=h_pyramid, liquid_height=liquid_height)

  # Liquid height extends into the cuboid
  return compute_pyramid_volume(base_area=x*y, h_pyramid=h_pyramid, liquid_height=h_pyramid) + \
    compute_cuboid_volume(x=x, y=y, z=h_cube, liquid_height=liquid_height - h_pyramid)

The downside is having to do both compute_volume_from_height and compute_height_from_volume, rather than a list of sections. But I think there is more flexibility, and ultimately less code when you want to do custom stuff.

rickwierenga commented 1 month ago

turns out @fderop has already written some of these and will PR them soon. <3

rickwierenga commented 1 month ago

as @BioCam pointed out, frustrum of a cone, frustrums of cylinders are also cylinders smh

fderop commented 1 month ago

as @BioCam pointed out, frustrum of a cone, frustrums of cylinders are also cylinders smh

I will also point out that it's a frustum, not frustRum 😂