From 3e57a69a349f3ede168ef120c6dec13700c336db Mon Sep 17 00:00:00 2001 From: fderop Date: Mon, 3 Nov 2025 13:56:03 -0800 Subject: [PATCH 1/8] 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/8] 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 From c7f75a8300cc60a453b727edf7d9e8a164470d5f Mon Sep 17 00:00:00 2001 From: fderop Date: Sun, 9 Nov 2025 13:44:38 -0800 Subject: [PATCH 3/8] correct --- pylabrobot/resources/agilent/plates.py | 73 +++++++++++--------------- 1 file changed, 32 insertions(+), 41 deletions(-) diff --git a/pylabrobot/resources/agilent/plates.py b/pylabrobot/resources/agilent/plates.py index fb6df6e6b7d..3f25036ef43 100644 --- a/pylabrobot/resources/agilent/plates.py +++ b/pylabrobot/resources/agilent/plates.py @@ -29,10 +29,39 @@ def _compute_height_from_volume_agilent_96_wellplate_150uL_Vb( ) -def agilent_96_wellplate_150uL_Ub(name: str) -> Plate: +def agilent_96_wellplate_150uL_Vb(name: str) -> Plate: """ Part number: 5042-8502 + Well Number | 96 + Well Form | Round + Well Diameter (A) | 6.4 mm + Well Bottom Shape | Conical + Well Volume | 150 µL + Well Working Volume | 120 µL + Well Depth (B) | 14.0 mm + Plate Height (C) | 15.9 mm + Plate Width (D) | 85.5 mm + Plate Length (E) | 127.8 mm + Row Distance (F) | 9 mm + Column Distance (G) | 9 mm + Row Offset (H) | 11.2 mm + Column Offset (I) | 14.4 mm + Frame Footprint | SBS + Frame Numbering | Alphanumeric + Skirted | Yes + Color | Clear + Material | Well: polypropylene + | Frame: polycarbonate + Temperature Range | -80 to 120 °C + Autoclavable | Yes + Sterile | Nonsterile + Stackable | Yes + Pack Size | 25, p/n 5042-8502 + Compatible Closing Mat | p/n 5067-5154 (not recommended for + | chromatography autosamplers) + Agilent Instrument Definition| Not applicable + https://www.agilent.com/cs/library/datasheets/public/ds-well-plate-specifications-5994-6035en-agilent.pdf """ @@ -45,44 +74,6 @@ def agilent_96_wellplate_150uL_Ub(name: str) -> Plate: "bottom_type": WellBottomType.U, "material_z_thickness": 0.88, # measured using z-probing "max_volume": 150, - } - - 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_Ub.__name__, - ordered_items=create_ordered_items_2d( - Well, - num_items_x=12, - num_items_y=8, - dx=14.4 - diameter / 2, # from spec - dy=11.2 - diameter / 2, # from spec - dz=16.0 - 14.0 - 0.88, # spec - spec - measured - item_dx=9.0, # standard - item_dy=9.0, # standard - **well_kwargs, - ), - 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, } @@ -98,9 +89,9 @@ def agilent_96_wellplate_150uL_Vb(name: str) -> Plate: Well, num_items_x=12, num_items_y=8, - dx=13.4 - diameter / 2, # measured + dx=14.4 - diameter / 2, # from spec dy=11.2 - diameter / 2, # from spec - dz=16.0 - 14.0 + 1, # spec - spec - measured + dz=16.0 - 14.0 + 1, # spec - spec - measured manually item_dx=9.0, # standard item_dy=9.0, # standard **well_kwargs, From b4bb324adc9b2a7a6a5a0dde9f17170c5c8c4894 Mon Sep 17 00:00:00 2001 From: Rick Wierenga Date: Sun, 9 Nov 2025 16:47:20 -0800 Subject: [PATCH 4/8] format --- pylabrobot/resources/agilent/plates.py | 6 +++--- pylabrobot/resources/height_volume_functions.py | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/pylabrobot/resources/agilent/plates.py b/pylabrobot/resources/agilent/plates.py index 3f25036ef43..68a249f141b 100644 --- a/pylabrobot/resources/agilent/plates.py +++ b/pylabrobot/resources/agilent/plates.py @@ -1,10 +1,10 @@ -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, ) +from pylabrobot.resources.plate import Plate +from pylabrobot.resources.utils import create_ordered_items_2d +from pylabrobot.resources.well import Well, WellBottomType def _compute_volume_from_height_agilent_96_wellplate_150uL_Vb( diff --git a/pylabrobot/resources/height_volume_functions.py b/pylabrobot/resources/height_volume_functions.py index 46c49ca04e0..6efa66d8c3b 100644 --- a/pylabrobot/resources/height_volume_functions.py +++ b/pylabrobot/resources/height_volume_functions.py @@ -510,8 +510,6 @@ def calculate_liquid_volume_container_1segment_round_vbottom( 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 de561428e3d05ab0e768e9418c3e7ece4f1737d0 Mon Sep 17 00:00:00 2001 From: Rick Wierenga Date: Sun, 9 Nov 2025 16:47:45 -0800 Subject: [PATCH 5/8] add deprecation warning for agilent_96_wellplate_150uL_Ub --- pylabrobot/resources/agilent/plates.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pylabrobot/resources/agilent/plates.py b/pylabrobot/resources/agilent/plates.py index 68a249f141b..09e19832105 100644 --- a/pylabrobot/resources/agilent/plates.py +++ b/pylabrobot/resources/agilent/plates.py @@ -1,3 +1,5 @@ +import warnings + from pylabrobot.resources.height_volume_functions import ( calculate_liquid_height_container_1segment_round_vbottom, calculate_liquid_volume_container_1segment_round_vbottom, @@ -98,3 +100,12 @@ def agilent_96_wellplate_150uL_Vb(name: str) -> Plate: ), plate_type="skirted", ) + + +def agilent_96_wellplate_150uL_Ub(name: str) -> Plate: + """Deprecated for agilent_96_wellplate_150uL_Vb. Use that one instead.""" + warnings.warn( + "agilent_96_wellplate_150uL_Ub is deprecated. Use agilent_96_wellplate_150uL_Vb instead.", + DeprecationWarning, + ) + return agilent_96_wellplate_150uL_Vb(name) From 69859d5956a12709ce6d368e62828dda78a18dee Mon Sep 17 00:00:00 2001 From: Rick Wierenga Date: Sun, 9 Nov 2025 16:48:37 -0800 Subject: [PATCH 6/8] revert dz --- pylabrobot/resources/agilent/plates.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylabrobot/resources/agilent/plates.py b/pylabrobot/resources/agilent/plates.py index 09e19832105..0d9535c7367 100644 --- a/pylabrobot/resources/agilent/plates.py +++ b/pylabrobot/resources/agilent/plates.py @@ -93,7 +93,7 @@ def agilent_96_wellplate_150uL_Vb(name: str) -> Plate: num_items_y=8, dx=14.4 - diameter / 2, # from spec dy=11.2 - diameter / 2, # from spec - dz=16.0 - 14.0 + 1, # spec - spec - measured manually + dz=15.9 - 14.0 - 0.88, # spec - spec - measured manually item_dx=9.0, # standard item_dy=9.0, # standard **well_kwargs, From 0a1a8d5c4e214f88f22b90bb0b0c4cb46956f514 Mon Sep 17 00:00:00 2001 From: Rick Wierenga Date: Sun, 9 Nov 2025 16:49:15 -0800 Subject: [PATCH 7/8] update docs --- docs/resources/library/agilent.md | 2 +- ...0uL_Ub.jpg => agilent_96_wellplate_150uL_Vb.jpg} | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/resources/library/img/agilent/{agilent_96_wellplate_150uL_Ub.jpg => agilent_96_wellplate_150uL_Vb.jpg} (100%) diff --git a/docs/resources/library/agilent.md b/docs/resources/library/agilent.md index 5131d14b33e..c1a09ced213 100644 --- a/docs/resources/library/agilent.md +++ b/docs/resources/library/agilent.md @@ -6,4 +6,4 @@ | Description | Image | PLR definition | |-|-|-| -| 'agilent_96_wellplate_150uL_Ub'
Part no.: 5042-8502
[manufacturer website](https://www.agilent.com/store/en_US/Prod-5042-8502/5042-8502) | ![](img/agilent/agilent_96_wellplate_150uL_Ub.jpg) | `agilent_96_wellplate_150uL_Ub` | +| 'agilent_96_wellplate_150uL_Vb'
Part no.: 5042-8502
[manufacturer website](https://www.agilent.com/store/en_US/Prod-5042-8502/5042-8502) | ![](img/agilent/agilent_96_wellplate_150uL_Vb.jpg) | `agilent_96_wellplate_150uL_Vb` | diff --git a/docs/resources/library/img/agilent/agilent_96_wellplate_150uL_Ub.jpg b/docs/resources/library/img/agilent/agilent_96_wellplate_150uL_Vb.jpg similarity index 100% rename from docs/resources/library/img/agilent/agilent_96_wellplate_150uL_Ub.jpg rename to docs/resources/library/img/agilent/agilent_96_wellplate_150uL_Vb.jpg From e46931374a577d22aec67da40405e8ce4adfecb5 Mon Sep 17 00:00:00 2001 From: Rick Wierenga Date: Sun, 9 Nov 2025 16:51:46 -0800 Subject: [PATCH 8/8] type --- pylabrobot/resources/height_volume_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylabrobot/resources/height_volume_functions.py b/pylabrobot/resources/height_volume_functions.py index 6efa66d8c3b..62f6bdb1212 100644 --- a/pylabrobot/resources/height_volume_functions.py +++ b/pylabrobot/resources/height_volume_functions.py @@ -456,7 +456,7 @@ def calculate_liquid_height_container_1segment_round_vbottom( check your labware definition and/or that you are using the right labware.""" ) - scale_factor = (liquid_volume / max_volume) ** (1 / 3) + scale_factor: float = (liquid_volume / max_volume) ** (1 / 3) liquid_height = scale_factor * h_pyramid return liquid_height