From 3e57a69a349f3ede168ef120c6dec13700c336db Mon Sep 17 00:00:00 2001 From: fderop Date: Mon, 3 Nov 2025 13:56:03 -0800 Subject: [PATCH 1/2] add --- pylabrobot/resources/agilent/plates.py | 68 ++++++++++++++++++- .../resources/height_volume_functions.py | 54 +++++++++++++++ 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/pylabrobot/resources/agilent/plates.py b/pylabrobot/resources/agilent/plates.py index 55685de6590..a67b2ef206c 100644 --- a/pylabrobot/resources/agilent/plates.py +++ b/pylabrobot/resources/agilent/plates.py @@ -1,13 +1,37 @@ from pylabrobot.resources.plate import Plate from pylabrobot.resources.utils import create_ordered_items_2d from pylabrobot.resources.well import Well, WellBottomType +from pylabrobot.resources.height_volume_functions import ( + calculate_liquid_height_container_1segment_round_vbottom, + calculate_liquid_volume_container_1segment_round_vbottom, +) + + +def _compute_volume_from_height_agilent_96_wellplate_150uL_Vb( + h: float, +): + # well depth: 12.5 mm + # well diameter at the top: 6.0 mm + if h > 12.5: + raise ValueError(f"Height {h} is too large for agilent_96_wellplate_150uL_Vb") + return calculate_liquid_volume_container_1segment_round_vbottom( + d=6.4, h_pyramid=12.5, liquid_height=h + ) + + +def _compute_height_from_volume_agilent_96_wellplate_150uL_Vb( + v: float, +): + if v > 150: + raise ValueError(f"Volume {v} is too large for agilent_96_wellplate_150uL_Vb") + return calculate_liquid_height_container_1segment_round_vbottom( + d=6.4, h_pyramid=12.5, liquid_volume=v + ) def agilent_96_wellplate_150uL_Ub(name: str) -> Plate: """ Part number: 5042-8502 - - https://www.agilent.com/cs/library/datasheets/public/ds-well-plate-specifications-5994-6035en-agilent.pdf """ diameter = 6.4 # from spec @@ -41,3 +65,43 @@ def agilent_96_wellplate_150uL_Ub(name: str) -> Plate: ), plate_type="skirted", ) + + +def agilent_96_wellplate_150uL_Vb(name: str) -> Plate: + """ + Part number: 5042-8502 + """ + + diameter = 6.4 # from spec + + well_kwargs = { + "size_x": diameter, # from spec + "size_y": diameter, # from spec + "size_z": 14.0, # from spec + "bottom_type": WellBottomType.V, + "material_z_thickness": 0.88, # measured using z-probing + "max_volume": 150, + "compute_volume_from_height": _compute_volume_from_height_agilent_96_wellplate_150uL_Vb, + "compute_height_from_volume": _compute_height_from_volume_agilent_96_wellplate_150uL_Vb, + } + + return Plate( + name=name, + size_x=127.8, # standard + size_y=85.5, # standard + size_z=15.9, # from spec + lid=None, + model=agilent_96_wellplate_150uL_Vb.__name__, + ordered_items=create_ordered_items_2d( + Well, + num_items_x=12, + num_items_y=8, + dx=13.4 - diameter / 2, # measured + dy=11.2 - diameter / 2, # from spec + dz=16.0 - 14.0 + 1, # spec - spec - measured + item_dx=9.0, # standard + item_dy=9.0, # standard + **well_kwargs, + ), + plate_type="skirted", + ) diff --git a/pylabrobot/resources/height_volume_functions.py b/pylabrobot/resources/height_volume_functions.py index ee5e53f0cc0..46c49ca04e0 100644 --- a/pylabrobot/resources/height_volume_functions.py +++ b/pylabrobot/resources/height_volume_functions.py @@ -434,6 +434,33 @@ def calculate_liquid_height_container_1segment_round_fbottom( return liquid_height +def calculate_liquid_height_container_1segment_round_vbottom( + d: float, h_pyramid: float, liquid_volume: float +) -> float: + """Calculate the height of liquid in a container with a cylindrical pyramid (cone) shape. + + Parameters: + d: The diameter of the base of the cone in mm. + h_pyramid: The height of the cone in mm. + liquid_volume: The volume of the liquid in the container in cubic millimeters. + + Returns: + The height of the liquid in the container in mm. + """ + r = d / 2 + max_volume = (1 / 3) * math.pi * r**2 * h_pyramid + + if liquid_volume > max_volume: + raise ValueError( + """WARNING: Liquid overflow detected; + check your labware definition and/or that you are using the right labware.""" + ) + + scale_factor = (liquid_volume / max_volume) ** (1 / 3) + liquid_height = scale_factor * h_pyramid + return liquid_height + + def calculate_liquid_volume_container_1segment_round_fbottom( d: float, h_cylinder: float, liquid_height: float ) -> float: @@ -458,6 +485,33 @@ def calculate_liquid_volume_container_1segment_round_fbottom( return cylinder_liquid_volume +def calculate_liquid_volume_container_1segment_round_vbottom( + d: float, h_pyramid: float, liquid_height: float +) -> float: + """Calculate the volume of liquid in a container with a cylindrical pyramid (cone) shape. + + Parameters: + d: The diameter of the base of the cone in mm. + h_pyramid: The height of the cone in mm. + liquid_height: The height of the liquid in the container in mm. + + Returns: + The volume of the liquid in cubic millimeters. + """ + r = d / 2 + if liquid_height > h_pyramid: + raise ValueError( + """WARNING: Liquid overflow detected; + check your labware definition and/or that you are using the right labware.""" + ) + + scale_factor = liquid_height / h_pyramid + liquid_volume = (1 / 3) * math.pi * r**2 * h_pyramid * (scale_factor**3) + return liquid_volume + + + + ### Example of usage using a lambda function: # def Rectangular_Reservoir(name: str) -> Plate: # """ An 8 well reservoir with a 30mL volume. """ From 0fb4828d37b61fbbaea2306ca69783efae9edd27 Mon Sep 17 00:00:00 2001 From: fderop Date: Mon, 3 Nov 2025 15:16:25 -0800 Subject: [PATCH 2/2] revert --- pylabrobot/resources/agilent/plates.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pylabrobot/resources/agilent/plates.py b/pylabrobot/resources/agilent/plates.py index a67b2ef206c..fb6df6e6b7d 100644 --- a/pylabrobot/resources/agilent/plates.py +++ b/pylabrobot/resources/agilent/plates.py @@ -32,6 +32,8 @@ def _compute_height_from_volume_agilent_96_wellplate_150uL_Vb( def agilent_96_wellplate_150uL_Ub(name: str) -> Plate: """ Part number: 5042-8502 + + https://www.agilent.com/cs/library/datasheets/public/ds-well-plate-specifications-5994-6035en-agilent.pdf """ diameter = 6.4 # from spec